home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume23 / trn / part10 < prev    next >
Encoding:
Text File  |  1991-08-22  |  64.0 KB  |  2,651 lines

  1. This is a new archive version of TRN at patchlevel 3.
  2. The original posting took up Volume23, issues 60 to 73, with
  3. various problems.  These files replace those issues.
  4.  
  5. #! /bin/sh
  6. # This is a shell archive.  Remove anything before this line, then feed it
  7. # into a shell via "sh file" or similar.  To overwrite existing files,
  8. # type "sh file -c".
  9. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  10. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  11. # Contents:  head.c mt-read.c rcln.c search.c sw.c
  12. # Wrapped by rsalz@litchi.bbn.com on Fri Aug 23 16:39:00 1991
  13. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  14. echo If this archive is complete, you will see the following message:
  15. echo '          "shar: End of archive 10 (of 14)."'
  16. if test -f 'head.c' -a "${1}" != "-c" ; then 
  17.   echo shar: Will not clobber existing file \"'head.c'\"
  18. else
  19.   echo shar: Extracting \"'head.c'\" \(9017 characters\)
  20.   sed "s/^X//" >'head.c' <<'END_OF_FILE'
  21. X/* $Header: head.c,v 4.3.3.2 91/01/16 02:41:15 davison Trn $
  22. X *
  23. X * $Log:    head.c,v $
  24. X * Revision 4.3.3.2  91/01/16  02:41:15  davison
  25. X * Integrated rn patches 48-54.
  26. X * 
  27. X * Revision 4.3.3.1  90/07/21  20:19:26  davison
  28. X * Initial Trn Release
  29. X * 
  30. X * Revision 4.3.2.7  90/11/22  13:49:50  sob
  31. X * Added changes to make System V compilers happy.
  32. X * 
  33. X * Revision 4.3.2.6  90/10/01  01:59:10  sob
  34. X * Fixed possible core dump problem reported by geoff@desint.uucp
  35. X * 
  36. X * Revision 4.3.2.5  90/03/22  23:04:22  sob
  37. X * Fixes provided by Wayne Davison <drivax!davison>
  38. X * 
  39. X * Revision 4.3.2.4  89/11/27  01:30:35  sob
  40. X * Altered NNTP code per ideas suggested by Bela Lubkin
  41. X * <filbo@gorn.santa-cruz.ca.us>
  42. X * 
  43. X * Revision 4.3.2.3  89/11/26  22:53:52  sob
  44. X * Add new patches to make RRN be faster.
  45. X * 
  46. X * Revision 4.3.2.2  89/11/08  01:17:46  sob
  47. X * Added changes to insure that this will compile for RN or RRN with no
  48. X * changes to the source code.
  49. X * 
  50. X * Revision 4.3.2.1  89/11/06  00:37:18  sob
  51. X * Added RRN support from NNTP 1.5
  52. X * 
  53. X * Revision 4.3.1.2  85/05/10  13:47:25  lwall
  54. X * Added debugging stuff.
  55. X * 
  56. X * Revision 4.3.1.1  85/05/10  11:32:30  lwall
  57. X * Branch for patches.
  58. X * 
  59. X * Revision 4.3  85/05/01  11:38:21  lwall
  60. X * Baseline for release with 4.3bsd.
  61. X * 
  62. X */
  63. X
  64. X#include "EXTERN.h"
  65. X#include "common.h"
  66. X#include "artio.h"
  67. X#include "bits.h"
  68. X#ifdef SERVER
  69. X#include "server.h"
  70. X#endif
  71. X#include "util.h"
  72. X#include "INTERN.h"
  73. X#include "head.h"
  74. X
  75. Xbool first_one;        /* is this the 1st occurance of this header line? */
  76. X
  77. Xstatic char htypeix[26] =
  78. X    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  79. X
  80. Xvoid
  81. Xhead_init()
  82. X{
  83. X    register int i;
  84. X
  85. X    for (i=HEAD_FIRST+1; i<HEAD_LAST; i++)
  86. X    htypeix[*htype[i].ht_name - 'a'] = i;
  87. X}
  88. X
  89. X#ifdef DEBUGGING
  90. Xdumpheader(where)
  91. Xchar *where;
  92. X{
  93. X    register int i;
  94. X
  95. X    printf("header: %d %s", parsed_art, where);
  96. X
  97. X    for (i=0; i<HEAD_LAST; i++) {
  98. X    printf("%15s %4d %4d %03o\n",htype[i].ht_name,
  99. X        htype[i].ht_minpos,
  100. X        htype[i].ht_maxpos,
  101. X        htype[i].ht_flags) FLUSH;
  102. X    }
  103. X}
  104. X#endif
  105. X
  106. Xint
  107. Xset_line_type(bufptr,colon)
  108. Xchar *bufptr;
  109. Xregister char *colon;
  110. X{
  111. X    char lc[LONGKEY+3];
  112. X    register char *t, *f;
  113. X    register int i, len;
  114. X
  115. X    if (colon-bufptr > LONGKEY+2)
  116. X    return SOME_LINE;
  117. X
  118. X    for (t=lc,f=bufptr; f<colon; f++, t++) {
  119. X    if (isspace(*f))
  120. X    /* guard against space before : */
  121. X        break;
  122. X    *t = isupper(*f) ? tolower(*f) : *f;
  123. X    }
  124. X    *t = '\0';
  125. X    f = lc;                /* get lc into register */
  126. X    len = t - f;
  127. X
  128. X    /* now scan the headtype table, backwards so we don't have to supply an
  129. X     * extra terminating value, using first letter as index, and length as
  130. X     * optimization to avoid calling subroutine strEQ unnecessarily.  Hauls.
  131. X     */
  132. X    
  133. X    if (islower(*f)) {
  134. X    for (i = htypeix[*f - 'a']; *htype[i].ht_name == *f; --i) {
  135. X        if (len == htype[i].ht_length && strEQ(f, htype[i].ht_name)) {
  136. X        return i;
  137. X        }
  138. X    }
  139. X    }
  140. X    return SOME_LINE;
  141. X}
  142. X
  143. Xvoid
  144. Xstart_header(artnum)
  145. XART_NUM artnum;
  146. X{
  147. X    register int i;
  148. X
  149. X#ifdef DEBUGGING
  150. X    if (debug & 4)
  151. X    dumpheader("start_header\n");
  152. X#endif
  153. X    for (i=0; i<HEAD_LAST; i++) {
  154. X    htype[i].ht_minpos = -1;
  155. X    htype[i].ht_maxpos = 0;
  156. X    }
  157. X    in_header = SOME_LINE;
  158. X    first_one = FALSE;
  159. X#ifdef ASYNC_PARSE
  160. X    parsed_art = artnum;
  161. X#endif
  162. X}
  163. X
  164. Xbool
  165. Xparseline(art_buf,newhide,oldhide)
  166. Xchar *art_buf;
  167. Xint newhide, oldhide;
  168. X{
  169. X    if (*art_buf == ' ' || *art_buf == '\t')
  170. X                    /* header continuation line? */
  171. X    return oldhide;
  172. X    else {                /* maybe another header line */
  173. X    char *s;
  174. X
  175. X    if (first_one) {        /* did we just pass 1st occurance? */
  176. X        first_one = FALSE;
  177. X        htype[in_header].ht_maxpos = artpos;
  178. X                    /* remember where line left off */
  179. X    }
  180. X    s = index(art_buf,':');
  181. X    if (s == Nullch) {
  182. X                /* is it the end of the header? */
  183. X        htype[PAST_HEADER].ht_minpos =
  184. X        (*art_buf == '\n') ? ftell(artfp) : artpos;
  185. X                /* remember where body starts */
  186. X        in_header = PAST_HEADER;
  187. X    }
  188. X    else {    /* it is a new header line */
  189. X        in_header = set_line_type(art_buf,s);
  190. X        first_one = (htype[in_header].ht_minpos < 0);
  191. X        if (first_one)
  192. X        htype[in_header].ht_minpos = artpos;
  193. X#ifdef DEBUGGING
  194. X        if (debug & 4)
  195. X        dumpheader(art_buf);
  196. X#endif
  197. X        if (htype[in_header].ht_flags & HT_HIDE)
  198. X        return newhide;
  199. X    }
  200. X    }
  201. X    return FALSE;            /* don't hide this line */
  202. X}
  203. X
  204. X#ifdef ASYNC_PARSE
  205. Xint
  206. Xparse_maybe(artnum)
  207. XART_NUM artnum;
  208. X{
  209. X    char tmpbuf[LBUFLEN];
  210. X
  211. X    if (parsed_art == artnum)
  212. X    return 0;
  213. X    /* no maybe about it now */
  214. X#ifdef SERVER
  215. X    if (nntpopen(artnum,GET_HEADER) == Nullfp) {
  216. X#else
  217. X    if (artopen(artnum) == Nullfp) {
  218. X#endif
  219. X    return -1;
  220. X    }
  221. X    start_header(artnum);
  222. X    while (in_header) {
  223. X    artpos = ftell(artfp);
  224. X    if (fgets(tmpbuf,LBUFLEN,artfp) == Nullch)
  225. X        break;
  226. X    parseline(tmpbuf,FALSE,FALSE);
  227. X    }
  228. X    in_header = PAST_HEADER;
  229. X    return 0;
  230. X}
  231. X#endif
  232. X
  233. X/* get the subject line for an article */
  234. X
  235. Xchar *
  236. Xfetchsubj(artnum,current_subject,copy)
  237. XART_NUM artnum;                /* article to get subject from */
  238. Xbool current_subject;            /* is it in a parsed header? */
  239. Xbool copy;                /* do you want it savestr()ed? */
  240. X{
  241. X    char *s = Nullch, *t;
  242. X#ifdef SERVER
  243. X    static int xhdr = 1;        /* Can we use xhdr command? */
  244. X    int eoo;                /* End of server output */
  245. X    char ser_line[256];
  246. X#endif /* SERVER */
  247. X
  248. X#ifdef CACHESUBJ
  249. X    if (!subj_list) {
  250. X    register ART_NUM i;
  251. X    
  252. X
  253. X#ifndef lint
  254. X    subj_list =
  255. X      (char**)safemalloc((MEM_SIZE)((OFFSET(lastart)+2)*sizeof(char *)));
  256. X#endif /* lint */
  257. X    for (i=0; i<=OFFSET(lastart); i++)
  258. X        subj_list[i] = Nullch;
  259. X    }
  260. X    if (!artnum || artnum > lastart)
  261. X    s = nullstr;
  262. X    else
  263. X    s = subj_list[OFFSET(artnum)];
  264. X#endif
  265. X    if (s == Nullch) {
  266. X    if (current_subject) {
  267. X        s = fetchlines(artnum,SUBJ_LINE);
  268. X#ifdef CACHESUBJ
  269. X        subj_list[OFFSET(artnum)] = s;
  270. X#endif
  271. X    }
  272. X    else {
  273. X        s = safemalloc((MEM_SIZE)256);
  274. X        *s = '\0';
  275. X#ifdef SERVER
  276. X        if (xhdr) {
  277. X            sprintf(ser_line, "XHDR subject %ld", artnum);
  278. X            put_server(ser_line);
  279. X        if (get_server(ser_line, sizeof (ser_line)) >= 0) {
  280. X            if (ser_line[0] == CHAR_FATAL) {
  281. X                xhdr = 0;
  282. X            } else {
  283. X                while (get_server(ser_line, sizeof (ser_line)) >= 0) {
  284. X                if (ser_line[0] == '.')
  285. X                    break;
  286. X                else {
  287. X                    t = index(ser_line, ' ');
  288. X                    if (t++) {
  289. X                    strcpy(s, t);
  290. X                    if (t = index(s, '\r'))
  291. X                        *t = '\0';
  292. X                    }
  293. X                }
  294. X                }
  295. X            }
  296. X        } else {
  297. X            fprintf(stderr,
  298. X            "rrn: Unexpected close of server socket.\n");
  299. X            finalize(1);
  300. X        }
  301. X        }
  302. X
  303. X        if (!xhdr) {
  304. X        sprintf(ser_line, "HEAD %ld", artnum);
  305. X        put_server(ser_line);
  306. X        eoo = 0;
  307. X        if (get_server(ser_line, 256) >= 0 && ser_line[0] == CHAR_OK) {
  308. X            do {
  309. X            if (get_server(s, 256) < 0 || (*s == '.')) {
  310. X            strcpy(s, "Title: \n");
  311. X            eoo = 1;
  312. X                }
  313. X            } while (strnNE(s,"Title:",6) && strnNE(s,"Subject:",8));
  314. X
  315. X            if (!eoo)
  316. X            while (get_server(ser_line, sizeof (ser_line)) >= 0 &&
  317. X                ser_line[0] != '.');
  318. X            t = index(s,':')+1;
  319. X            while (*t == ' ') t++;
  320. X            strcpy(s, t);
  321. X            }
  322. X        }
  323. X#else /* not SERVER */
  324. X        if (artopen(artnum) != Nullfp) {
  325. X        do {
  326. X            if (fgets(s,256,artfp) == Nullch)
  327. X            strcpy(s, "Title: \n");
  328. X        } while (strnNE(s,"Title:",6) && strnNE(s,"Subject:",8));
  329. X
  330. X        s[strlen(s)-1] = '\0';
  331. X        t = index(s,':')+1;
  332. X        while (*t == ' ') t++;
  333. X        strcpy(s, t);
  334. X        }
  335. X#endif
  336. X        s = saferealloc(s, (MEM_SIZE)strlen(s)+1);
  337. X#ifdef CACHESUBJ
  338. X        subj_list[OFFSET(artnum)] = s;
  339. X#endif 
  340. X    }
  341. X    }
  342. X#ifdef CACHESUBJ
  343. X    if (copy) {
  344. X    t = savestr(s);
  345. X    return t;
  346. X    }
  347. X    else
  348. X    return s;
  349. X#else
  350. X    if (copy)
  351. X    return s;
  352. X    else {
  353. X    safecpy(cmd_buf,s,CBUFLEN);    /* hope this is okay--we're */
  354. X    free(s);
  355. X    return cmd_buf;            /* really scraping for space here */
  356. X    }
  357. X#endif
  358. X}
  359. X
  360. X/* get header lines from an article */
  361. X
  362. Xchar *
  363. Xfetchlines(artnum,which_line)
  364. XART_NUM artnum;                /* article to get line from */
  365. Xint which_line;                /* type of line desired */
  366. X{
  367. X    char *newbuf, *t, tmp_buf[LBUFLEN];
  368. X    register ART_POS curpos;
  369. X    int size;
  370. X    register ART_POS firstpos;
  371. X    register ART_POS lastpos;
  372. X    
  373. X#ifdef ASYNC_PARSE
  374. X    if (parse_maybe(artnum))
  375. X    artnum = 0;
  376. X#endif
  377. X    firstpos = htype[which_line].ht_minpos;
  378. X    lastpos = htype[which_line].ht_maxpos;
  379. X#ifdef SERVER
  380. X    if (!artnum || firstpos < 0 || nntpopen(artnum,GET_HEADER) == Nullfp) {
  381. X#else
  382. X    if (!artnum || firstpos < 0 || artopen(artnum) == Nullfp) {
  383. X#endif
  384. X    newbuf = safemalloc((unsigned int)1);
  385. X    *newbuf = '\0';
  386. X    return newbuf;
  387. X    }
  388. X#ifndef lint
  389. X    size = lastpos - firstpos + 1;
  390. X#else
  391. X    size = Null(int);
  392. X#endif /* lint */
  393. X#ifdef DEBUGGING
  394. X    if (debug && (size < 1 || size > 1000)) {
  395. X    printf("Firstpos = %ld, lastpos = %ld\n",(long)firstpos,(long)lastpos);
  396. X    gets(tmp_buf);
  397. X    }
  398. X#endif
  399. X    newbuf = safemalloc((unsigned int)size);
  400. X    *newbuf = '\0';
  401. X    fseek(artfp,firstpos,0);
  402. X    for (curpos = firstpos; curpos < lastpos; curpos = ftell(artfp)) {
  403. X    if (fgets(tmp_buf,LBUFLEN,artfp) == Nullch)
  404. X        break;
  405. X    if (*tmp_buf == ' ' || *tmp_buf == '\t')
  406. X        t = tmp_buf;
  407. X    else {
  408. X        t = index(tmp_buf,':');
  409. X        if (t == Nullch)
  410. X        break;
  411. X        t++;
  412. X    }
  413. X    while (*t == ' ' || *t == '\t') t++;
  414. X    safecat(newbuf,t,size);
  415. X    }
  416. X    return newbuf;
  417. X}
  418. X
  419. END_OF_FILE
  420.   if test 9017 -ne `wc -c <'head.c'`; then
  421.     echo shar: \"'head.c'\" unpacked with wrong size!
  422.   fi
  423.   # end of 'head.c'
  424. fi
  425. if test -f 'mt-read.c' -a "${1}" != "-c" ; then 
  426.   echo shar: Will not clobber existing file \"'mt-read.c'\"
  427. else
  428.   echo shar: Extracting \"'mt-read.c'\" \(12741 characters\)
  429.   sed "s/^X//" >'mt-read.c' <<'END_OF_FILE'
  430. X/* $Header: mt-read.c,v 4.3.3.2 91/01/16 02:49:15 davison Trn $
  431. X**
  432. X** $Log:    mt-read.c,v $
  433. X** Revision 4.3.3.2  91/01/16  02:49:15  davison
  434. X** Changed Free() to safefree().  Tweaked fopen for possible binary open mode.
  435. X** 
  436. X** Revision 4.3.3.1  90/07/24  23:51:12  davison
  437. X** Initial Trn Release
  438. X** 
  439. X*/
  440. X
  441. X#include "EXTERN.h"
  442. X#include "common.h"
  443. X#include "mthreads.h"
  444. X
  445. Xstatic FILE *fp_in;
  446. X
  447. Xvoid tweak_roots();
  448. X
  449. X/* Attempt to open the thread file.  If it's there, only grab the totals
  450. X** from the start of the file.  This should give them enough information
  451. X** to decide if they need to read the whole thing into memory.
  452. X*/
  453. Xint
  454. Xinit_data( filename )
  455. Xchar *filename;
  456. X{
  457. X    root_root = Null(ROOT*);
  458. X    author_root = Null(AUTHOR*);
  459. X    unk_domain.ids = Nullart;
  460. X    unk_domain.link = Null(DOMAIN*);
  461. X
  462. X    if( (fp_in = fopen( filename, FOPEN_RB )) == Nullfp ) {
  463. X    bzero( &total, sizeof (TOTAL) );
  464. X    return 0;
  465. X    }
  466. X    if( fread( &total, 1, sizeof (TOTAL), fp_in ) < sizeof (TOTAL) ) {
  467. X    fclose( fp_in );
  468. X    bzero( &total, sizeof (TOTAL) );
  469. X    return 0;
  470. X    }
  471. X    return 1;
  472. X}
  473. X
  474. X/* They want everything.  Read in the packed information and transform it
  475. X** into a set of linked structures that is easily manipulated.
  476. X*/
  477. Xint
  478. Xread_data()
  479. X{
  480. X    if( read_authors()
  481. X     && read_subjects()
  482. X     && read_roots()
  483. X     && read_articles()
  484. X     && read_ids() )
  485. X    {
  486. X    tweak_roots();
  487. X    fclose( fp_in );
  488. X    return 1;
  489. X    }
  490. X    /* Something failed.  Safefree takes care of checking if we're partially
  491. X    ** allocated.  Any linked-list structures we created were freed before
  492. X    ** we got here.
  493. X    */
  494. X    safefree( &strings );
  495. X    safefree( &subject_cnts );
  496. X    safefree( &author_cnts );
  497. X    safefree( &root_array );
  498. X    safefree( &subject_array );
  499. X    safefree( &article_array );
  500. X    safefree( &ids );
  501. X    fclose( fp_in );
  502. X    return 0;
  503. X}
  504. X
  505. X/* They don't want to read the data.  Close the file if we opened it.
  506. X*/
  507. Xvoid
  508. Xdont_read_data( open_flag )
  509. Xint open_flag;        /* 0 == not opened, 1 == open failed, 2 == open */
  510. X{
  511. X    if( open_flag == 2 ) {
  512. X    fclose( fp_in );
  513. X    }
  514. X}
  515. X
  516. X#define give_string_to( dest )    /* Comment for makedepend to     \
  517. X                ** ignore the backslash above */ \
  518. X{\
  519. X    register MEM_SIZE len = strlen( string_ptr ) + 1;\
  520. X    dest = safemalloc( len );\
  521. X    bcopy( string_ptr, dest, (int)len );\
  522. X    string_ptr += len;\
  523. X}
  524. X
  525. Xchar *subject_strings;
  526. X
  527. X/* The author information is an array of use-counts, followed by all the
  528. X** null-terminated strings crammed together.  The subject strings are read
  529. X** in at the same time, since they are appended to the end of the author
  530. X** strings.
  531. X*/
  532. Xint
  533. Xread_authors()
  534. X{
  535. X    register int count;
  536. X    register char *string_ptr;
  537. X    register WORD *authp;
  538. X    register AUTHOR *author, *last_author, **author_ptr;
  539. X
  540. X    if( !read_item( &author_cnts, (MEM_SIZE)total.author * sizeof (WORD) )
  541. X     || !read_item( &strings, total.string1 ) ) {
  542. X    return 0;
  543. X    }
  544. X
  545. X    /* We'll use this array to point each article at its proper author
  546. X    ** (packed values are saved as indexes).
  547. X    */
  548. X    author_array = (AUTHOR**)safemalloc( total.author * sizeof (AUTHOR*) );
  549. X    author_ptr = author_array;
  550. X
  551. X    authp = author_cnts;
  552. X    string_ptr = strings;
  553. X
  554. X    last_author = Null(AUTHOR*);
  555. X    for( count = total.author; count--; ) {
  556. X    *author_ptr++ = author = (AUTHOR*)safemalloc( sizeof (AUTHOR) );
  557. X    if( !last_author ) {
  558. X        author_root = author;
  559. X    } else {
  560. X        last_author->link = author;
  561. X    }
  562. X    give_string_to( author->name );
  563. X    author->count = *authp++;
  564. X    last_author = author;
  565. X    }
  566. X    last_author->link = Null(AUTHOR*);
  567. X
  568. X    subject_strings = string_ptr;
  569. X
  570. X    free( author_cnts );
  571. X    author_cnts = Null(WORD*);
  572. X
  573. X    return 1;
  574. X}
  575. X
  576. X/* The subject values consist of the crammed-together null-terminated strings
  577. X** (already read in above) and the use-count array.  They were saved in the
  578. X** order that the roots will need when they are unpacked.
  579. X*/
  580. Xint
  581. Xread_subjects()
  582. X{
  583. X    if( !read_item( &subject_cnts, (MEM_SIZE)total.subject * sizeof (WORD) ) ) {
  584. X    return 0;
  585. X    }
  586. X    return 1;
  587. X}
  588. X
  589. X/* Read in the packed root structures and recreate the linked list versions,
  590. X** processing each root's subjects as we go.  Defer interpretation of article
  591. X** offsets until we unpack the article structures.
  592. X*/
  593. Xint
  594. Xread_roots()
  595. X{
  596. X    register int count;
  597. X    register char *string_ptr;
  598. X    register WORD *subjp;
  599. X    ROOT *root, *last_root, **root_ptr;
  600. X    SUBJECT *subject, *last_subject, **subj_ptr;
  601. X    int ret;
  602. X
  603. X    /* Use this array when unpacking the article's subject offsets. */
  604. X    subject_array = (SUBJECT**)safemalloc( total.subject * sizeof (SUBJECT*) );
  605. X    subj_ptr = subject_array;
  606. X    /* And this array points the article's root offsets that the right spot. */
  607. X    root_array = (ROOT**)safemalloc( total.root * sizeof (ROOT*) );
  608. X    root_ptr = root_array;
  609. X
  610. X    subjp = subject_cnts;
  611. X    string_ptr = subject_strings;
  612. X
  613. X#ifndef lint
  614. X    last_root = (ROOT*)&root_root;
  615. X#else
  616. X    last_root = Null(ROOT*);
  617. X#endif
  618. X    for( count = total.root; count--; ) {
  619. X    ret = fread( &p_root, 1, sizeof (PACKED_ROOT), fp_in );
  620. X    if( ret != sizeof (PACKED_ROOT) ) {
  621. X        log_error( "failed root read --  %d bytes instead of %d.\n",
  622. X        ret, sizeof (PACKED_ROOT) );
  623. X        ret = 0;
  624. X        /* Free the roots we've read so far and their subjects. */
  625. X        while( root_ptr != root_array ) {
  626. X        free( *--root_ptr );
  627. X        }
  628. X        while( subj_ptr != subject_array ) {
  629. X        free( (*--subj_ptr)->str );
  630. X        free( *subj_ptr );
  631. X        }
  632. X        goto finish_up;
  633. X    }
  634. X    *root_ptr++ = root = (ROOT*)safemalloc( sizeof (ROOT) );
  635. X    root->link = Null(ROOT*);
  636. X    root->seq = p_root.articles;
  637. X    root->root_num = p_root.root_num;
  638. X    root->thread_cnt = p_root.thread_cnt;
  639. X    root->subject_cnt = p_root.subject_cnt;
  640. X    last_subject = Null(SUBJECT*);
  641. X    while( p_root.subject_cnt-- ) {
  642. X        *subj_ptr++ = subject = (SUBJECT*)safemalloc( sizeof (SUBJECT) );
  643. X        if( !last_subject ) {
  644. X        root->subjects = subject;
  645. X        } else {
  646. X        last_subject->link = subject;
  647. X        }
  648. X        give_string_to( subject->str );
  649. X        subject->count = *subjp++;
  650. X        last_subject = subject;
  651. X    }
  652. X    last_subject->link = Null(SUBJECT*);
  653. X    last_root->link = root;
  654. X    last_root = root;
  655. X    }
  656. X    ret = 1;
  657. X
  658. X  finish_up:
  659. X    free( subject_cnts );
  660. X    free( strings );
  661. X    subject_cnts = Null(WORD*);
  662. X    strings = Nullch;
  663. X
  664. X    return ret;
  665. X}
  666. X
  667. X/* A simple routine that checks the validity of the article's subject value.
  668. X** A -1 means that it is NULL, otherwise it should be an offset into the
  669. X** subject array we just unpacked.
  670. X*/
  671. XSUBJECT *
  672. Xvalid_subject( num, art_num )
  673. XWORD num;
  674. Xlong art_num;
  675. X{
  676. X    if( num == -1 ) {
  677. X    return Null(SUBJECT*);
  678. X    }
  679. X    if( num < 0 || num >= total.subject ) {
  680. X    log_error( "Invalid subject in data file: %d [%ld]\n", num, art_num );
  681. X    return Null(SUBJECT*);
  682. X    }
  683. X    return subject_array[num];
  684. X}
  685. X
  686. X/* Ditto for author checking. */
  687. XAUTHOR *
  688. Xvalid_author( num, art_num )
  689. XWORD num;
  690. Xlong art_num;
  691. X{
  692. X    if( num == -1 ) {
  693. X    return Null(AUTHOR*);
  694. X    }
  695. X    if( num < 0 || num >= total.author ) {
  696. X    log_error( "Invalid author in data file: %d [%ld]\n", num, art_num );
  697. X    return Null(AUTHOR*);
  698. X    }
  699. X    return author_array[num];
  700. X}
  701. X
  702. X/* Our parent/sibling information is a relative offset in the article array.
  703. X** zero for none.  Child values are always found in the very next array
  704. X** element if child_cnt is non-zero.
  705. X*/
  706. X#define valid_node( rel, num ) (!(rel)? Nullart : article_array[(rel)+(num)])
  707. X
  708. X/* Read the articles into their linked lists.  Point everything everywhere. */
  709. Xint
  710. Xread_articles()
  711. X{
  712. X    register int count;
  713. X    register ARTICLE *article, **article_ptr;
  714. X    int ret;
  715. X
  716. X    /* Build an array to interpret interlinkages of articles. */
  717. X    article_array = (ARTICLE**)safemalloc( total.article * sizeof (ARTICLE*) );
  718. X    article_ptr = article_array;
  719. X
  720. X    /* Allocate all the structures up-front so that we can point to un-read
  721. X    ** siblings as we go.
  722. X    */
  723. X    for( count = total.article; count--; ) {
  724. X    *article_ptr++ = (ARTICLE*)safemalloc( sizeof (ARTICLE) );
  725. X    }
  726. X    article_ptr = article_array;
  727. X    for( count = 0; count < total.article; count++ ) {
  728. X    ret = fread( &p_article, 1, sizeof (PACKED_ARTICLE), fp_in );
  729. X    if( ret != sizeof (PACKED_ARTICLE) ) {
  730. X        log_error( "failed article read --  %d bytes instead of %d.\n", ret, sizeof (PACKED_ARTICLE) );
  731. X        ret = 0;
  732. X        goto finish_up;
  733. X    }
  734. X    article = *article_ptr++;
  735. X    article->num = p_article.num;
  736. X    article->date = p_article.date;
  737. X    article->subject = valid_subject( p_article.subject, p_article.num );
  738. X    article->author = valid_author( p_article.author, p_article.num );
  739. X    article->flags = p_article.flags;
  740. X    article->child_cnt = p_article.child_cnt;
  741. X    article->parent = valid_node( p_article.parent, count );
  742. X    article->children = article->child_cnt?article_array[count+1]:Nullart;
  743. X    article->siblings = valid_node( p_article.siblings, count );
  744. X    article->root = root_array[p_article.root];
  745. X    }
  746. X    ret = 1;
  747. X
  748. X  finish_up:
  749. X    /* We're done with most of the pointer arrays. */
  750. X    free( root_array );
  751. X    free( subject_array );
  752. X    free( author_array );
  753. X    root_array = Null(ROOT**);
  754. X    subject_array = Null(SUBJECT**);
  755. X    author_array = Null(AUTHOR**);
  756. X
  757. X    return ret;
  758. X}
  759. X
  760. X/* Read the message-id strings and attach them to each article.  The data
  761. X** format consists of the mushed-together null-terminated strings (a domain
  762. X** name followed by all its unique-id prefixes) and then the article offsets
  763. X** to which they belong.  The first domain name was omitted, as it is the
  764. X** ".unknown." domain for those truly weird message-id's without '@'s.
  765. X*/
  766. Xint
  767. Xread_ids()
  768. X{
  769. X    register DOMAIN *domain, *last;
  770. X    register ARTICLE *article;
  771. X    register char *string_ptr;
  772. X    register int i, count;
  773. X
  774. X    if( !read_item( &strings, total.string2 ) ) {
  775. X    return 0;
  776. X    }
  777. X    if( !read_item( &ids,
  778. X        (MEM_SIZE)(total.article+total.domain+1) * sizeof (WORD) ) ) {
  779. X    return 0;
  780. X    }
  781. X    string_ptr = strings;
  782. X
  783. X    last = Null(DOMAIN*);
  784. X    for( i = 0, count = total.domain + 1; count--; i++ ) {
  785. X    if( i ) {
  786. X        domain = (DOMAIN*)safemalloc( sizeof (DOMAIN) );
  787. X        give_string_to( domain->name );
  788. X    } else {
  789. X        domain = &unk_domain;
  790. X    }
  791. X    if( ids[i] == -1 ) {
  792. X        domain->ids = Nullart;
  793. X    } else {
  794. X        article = article_array[ids[i]];
  795. X        domain->ids = article;
  796. X        for( ;; ) {
  797. X        give_string_to( article->id );
  798. X        article->domain = domain;
  799. X        if( ids[++i] != -1 ) {
  800. X            article = article->id_link = article_array[ids[i]];
  801. X        } else {
  802. X            article->id_link = Nullart;
  803. X            break;
  804. X        }
  805. X        }
  806. X    }
  807. X    if( last ) {
  808. X        last->link = domain;
  809. X    }
  810. X    last = domain;
  811. X    }
  812. X    last->link = Null(DOMAIN*);
  813. X    free( ids );
  814. X    free( strings );
  815. X    ids = Null(WORD*);
  816. X    strings = Nullch;
  817. X
  818. X    return 1;
  819. X}
  820. X
  821. X/* And finally, point all the roots at their root articles and get rid
  822. X** of anything left over that was used to aid our unpacking.
  823. X*/
  824. Xvoid
  825. Xtweak_roots()
  826. X{
  827. X    register ROOT *root;
  828. X
  829. X    for( root = root_root; root; root = root->link ) {
  830. X    root->articles = article_array[root->seq];
  831. X    }
  832. X    free( article_array );
  833. X    article_array = Null(ARTICLE**);
  834. X}
  835. X
  836. X/* A short-hand for reading a chunk of the file into a malloc'ed array.
  837. X*/
  838. Xint
  839. Xread_item( dest, len )
  840. Xchar **dest;
  841. XMEM_SIZE len;
  842. X{
  843. X    int ret;
  844. X
  845. X    *dest = safemalloc( len );
  846. X    ret = fread( *dest, 1, (int)len, fp_in );
  847. X    if( ret != len ) {
  848. X    log_error( "Only read %ld bytes instead of %ld.\n",
  849. X        (long)ret, (long)len );
  850. X    free( *dest );
  851. X    *dest = Nullch;
  852. X    return 0;
  853. X    }
  854. X    return 1;
  855. X}
  856. X
  857. X/* Interpret rn's '%X' and '%x' path prefixes without including all their
  858. X** source.  Names that don't start with '%' or '/' are prefixed with the
  859. X** SPOOL directory.
  860. X*/
  861. Xchar *
  862. Xfile_exp( name )
  863. Xchar *name;
  864. X{
  865. X    static char name_buff[256];
  866. X
  867. X    if( *name == '/' ) {    /* fully qualified names are left alone */
  868. X    return name;
  869. X    } else if( *name != '%' ) {    /* all normal names are relative to SPOOL */
  870. X    sprintf( name_buff, "%s/%s", SPOOL, name );
  871. X    } else {            /* interpret %x (LIB) & %X (RNLIB) */
  872. X    if( name[1] == 'x' ) {
  873. X        strcpy( name_buff, LIB );
  874. X    } else if( name[1] == 'X' ) {
  875. X        strcpy( name_buff, RNLIB );
  876. X    } else {
  877. X        log_entry( "Unknown expansion: %s", name );
  878. X        exit( 1 );
  879. X    }
  880. X    strcat( name_buff, name+2 );
  881. X    }
  882. X    return name_buff;
  883. X}
  884. X
  885. X#ifndef lint
  886. X/* A malloc that bombs-out when memory is exhausted. */
  887. Xchar *
  888. Xsafemalloc( amount )
  889. XMEM_SIZE amount;
  890. X{
  891. X    register char *cp;
  892. X    extern char *malloc();
  893. X
  894. X    if( (cp = malloc( amount )) == Nullch ) {
  895. X    log_error( "malloc(%ld) failed.\n", (long)amount );
  896. X    exit( 1 );
  897. X    }
  898. X    return cp;
  899. X}
  900. X#endif
  901. X
  902. X/* Create a malloc'ed copy of a string. */
  903. Xchar *
  904. Xsavestr( str )
  905. Xchar *str;
  906. X{
  907. X    register MEM_SIZE len = strlen( str ) + 1;
  908. X    register char *newaddr = safemalloc( len );
  909. X
  910. X    bcopy( str, newaddr, (int)len );
  911. X
  912. X    return newaddr;
  913. X}
  914. X
  915. X#ifndef lint
  916. X/* Free some memory if it hasn't already been freed. */
  917. Xvoid
  918. Xsafefree( pp )
  919. Xchar **pp;
  920. X{
  921. X    if( *pp ) {
  922. X    free( *pp );
  923. X    *pp = Nullch;
  924. X    }
  925. X}
  926. X#endif
  927. END_OF_FILE
  928.   if test 12741 -ne `wc -c <'mt-read.c'`; then
  929.     echo shar: \"'mt-read.c'\" unpacked with wrong size!
  930.   fi
  931.   # end of 'mt-read.c'
  932. fi
  933. if test -f 'rcln.c' -a "${1}" != "-c" ; then 
  934.   echo shar: Will not clobber existing file \"'rcln.c'\"
  935. else
  936.   echo shar: Extracting \"'rcln.c'\" \(13006 characters\)
  937.   sed "s/^X//" >'rcln.c' <<'END_OF_FILE'
  938. X/* $Header: rcln.c,v 4.3.3.2 90/08/20 16:46:05 davison Trn $
  939. X *
  940. X * $Log:    rcln.c,v $
  941. X * Revision 4.3.3.2  90/08/20  16:46:05  davison
  942. X * Removed extraneous xref boundary check.
  943. X * 
  944. X * Revision 4.3.3.1  90/06/20  22:39:19  davison
  945. X * Initial Trn Release
  946. X * 
  947. X * Revision 4.3.2.1  90/04/23  00:22:22  sob
  948. X * Changed atoi to atol and fixed RCS information.
  949. X * 
  950. X * Revision 4.3.1.2  85/07/23  17:39:08  lwall
  951. X * Oops, was freeing a static buf on -c in checkexpired.
  952. X * 
  953. X * Revision 4.3.1.1  85/05/10  11:37:08  lwall
  954. X * Branch for patches.
  955. X * 
  956. X * Revision 4.3  85/05/01  11:45:36  lwall
  957. X * Baseline for release with 4.3bsd.
  958. X * 
  959. X */
  960. X
  961. X#include "EXTERN.h"
  962. X#include "common.h"
  963. X#include "util.h"
  964. X#include "rcstuff.h"
  965. X#include "ngdata.h"
  966. X#include "INTERN.h"
  967. X#include "rcln.h"
  968. X
  969. Xvoid
  970. Xrcln_init()
  971. X{
  972. X    ;
  973. X}
  974. X
  975. X#ifdef CATCHUP
  976. Xvoid
  977. Xcatch_up(ngx)
  978. XNG_NUM ngx;
  979. X{
  980. X    char tmpbuf[128];
  981. X    char *tmpp;
  982. X    
  983. X#ifdef VERBOSE
  984. X    IF(verbose)
  985. X    printf("\nMarking %s as all read.\n",rcline[ngx]) FLUSH;
  986. X    ELSE
  987. X#endif
  988. X#ifdef TERSE
  989. X    fputs("\nMarked read\n",stdout) FLUSH;
  990. X#endif
  991. X    sprintf(tmpbuf,"%s: 1-%ld", rcline[ngx],(long)getngsize(ngx));
  992. X    free(rcline[ngx]);
  993. X    rcline[ngx] = savestr(tmpbuf);
  994. X    tmpp = rcline[ngx] + rcnums[ngx] - 1;
  995. X    *tmpp = '\0';
  996. X    write_rc();
  997. X}
  998. X#endif
  999. X
  1000. X/* add an article number to a newsgroup, if it isn't already read */
  1001. X
  1002. Xint
  1003. Xaddartnum(artnum,ngnam)
  1004. XART_NUM artnum;
  1005. Xchar *ngnam;
  1006. X{
  1007. X    register NG_NUM ngnum = find_ng(ngnam);
  1008. X    register char *s, *t, *maxt = Nullch;
  1009. X    ART_NUM min = 0, max = -1, lastnum = 0;
  1010. X    char *mbuf;
  1011. X    bool morenum;
  1012. X
  1013. X    if (!artnum)
  1014. X    return 0;
  1015. X    if (ngnum == nextrcline || !rcnums[ngnum])
  1016. X                    /* not found in newsrc? */
  1017. X    return 0;
  1018. X#ifdef CACHEFIRST
  1019. X    if (!abs1st[ngnum])
  1020. X#else
  1021. X    if (!toread[ngnum])
  1022. X#endif
  1023. X                    /* now is a good time to trim down */
  1024. X    set_toread(ngnum);        /* the list due to expires if we */
  1025. X                    /* have not yet. */
  1026. X#if defined(DEBUGGING) && !defined(USETHREADS)
  1027. X    if (artnum > ngmax[ngnum] + 10    /* allow for incoming articles */
  1028. X       ) {
  1029. X    printf("\nCorrupt Xref line!!!  %ld --> %s(1..%ld)\n",
  1030. X        artnum,ngnam,
  1031. X        ngmax[ngnum]) FLUSH;
  1032. X    paranoid = TRUE;        /* paranoia reigns supreme */
  1033. X    return -1;            /* hope this was the first newsgroup */
  1034. X    }
  1035. X#endif
  1036. X
  1037. X    if (toread[ngnum] == TR_BOGUS)
  1038. X    return 0;
  1039. X#ifdef DEBUGGING
  1040. X    if (debug & DEB_XREF_MARKER) {
  1041. X    printf("%ld->\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
  1042. X      rcline[ngnum] + rcnums[ngnum]) FLUSH;
  1043. X    }
  1044. X#endif
  1045. X    s = rcline[ngnum] + rcnums[ngnum];
  1046. X    while (*s == ' ') s++;        /* skip spaces */
  1047. X    t = s;
  1048. X    while (isdigit(*s) && artnum >= (min = atol(s))) {
  1049. X                    /* while it might have been read */
  1050. X    for (t = s; isdigit(*t); t++) ;    /* skip number */
  1051. X    if (*t == '-') {        /* is it a range? */
  1052. X        t++;            /* skip to next number */
  1053. X        if (artnum <= (max = atol(t)))
  1054. X        return 0;        /* it is in range => already read */
  1055. X        lastnum = max;        /* remember it */
  1056. X        maxt = t;            /* remember position in case we */
  1057. X                    /* want to overwrite the max */
  1058. X        while (isdigit(*t)) t++;    /* skip second number */
  1059. X    }
  1060. X    else {
  1061. X        if (artnum == min)        /* explicitly a read article? */
  1062. X        return 0;
  1063. X        lastnum = min;        /* remember what the number was */
  1064. X        maxt = Nullch;        /* last one was not a range */
  1065. X    }
  1066. X    while (*t && !isdigit(*t)) t++;    /* skip comma and any spaces */
  1067. X    s = t;
  1068. X    }
  1069. X    
  1070. X    /* we have not read it, so insert the article number before s */
  1071. X    
  1072. X    morenum = isdigit(*s);        /* will it need a comma after? */
  1073. X    *(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
  1074. X    mbuf = safemalloc((MEM_SIZE)(strlen(s) + (s-rcline[ngnum]) + 8));
  1075. X    strcpy(mbuf,rcline[ngnum]);        /* make new rc line */
  1076. X    if (maxt && lastnum && artnum == lastnum+1)
  1077. X                        /* can we just extend last range? */
  1078. X    t = mbuf + (maxt-rcline[ngnum]);/* then overwrite previous max */
  1079. X    else {
  1080. X    t = mbuf + (t-rcline[ngnum]);    /* point t into new line instead */
  1081. X    if (lastnum) {            /* have we parsed any line? */
  1082. X        if (!morenum)        /* are we adding to the tail? */
  1083. X        *t++ = ',';        /* supply comma before */
  1084. X        if (!maxt && artnum == lastnum+1 && *(t-1) == ',')
  1085. X                    /* adjacent singletons? */
  1086. X        *(t-1) = '-';        /* turn them into a range */
  1087. X    }
  1088. X    }
  1089. X    if (morenum) {            /* is there more to life? */
  1090. X    if (min == artnum+1) {        /* can we consolidate further? */
  1091. X        bool range_before = (*(t-1) == '-');
  1092. X        bool range_after;
  1093. X        char *nextmax;
  1094. X
  1095. X        for (nextmax = s; isdigit(*nextmax); nextmax++) ;
  1096. X        range_after = *nextmax++ == '-';
  1097. X        
  1098. X        if (range_before)
  1099. X        *t = '\0';        /* artnum is redundant */
  1100. X        else
  1101. X        sprintf(t,"%ld-",(long)artnum);/* artnum will be new min */
  1102. X        
  1103. X        if (range_after)
  1104. X        s = nextmax;        /* *s is redundant */
  1105. X    /*  else
  1106. X        s = s */        /* *s is new max */
  1107. X    }
  1108. X    else
  1109. X        sprintf(t,"%ld,",(long)artnum);    /* put the number and comma */
  1110. X    }
  1111. X    else
  1112. X    sprintf(t,"%ld",(long)artnum);    /* put the number there (wherever) */
  1113. X    strcat(t,s);            /* copy remainder of line */
  1114. X#ifdef DEBUGGING
  1115. X    if (debug & DEB_XREF_MARKER) {
  1116. X    printf("%s\n",mbuf) FLUSH;
  1117. X    }
  1118. X#endif
  1119. X    free(rcline[ngnum]);
  1120. X    rcline[ngnum] = mbuf;        /* pull the switcheroo */
  1121. X    *(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
  1122. X                    /* wipe out : or ! */
  1123. X    if (toread[ngnum] > TR_NONE)    /* lest we turn unsub into bogus */
  1124. X    --toread[ngnum];
  1125. X    return 0;
  1126. X}
  1127. X
  1128. X#ifdef MCHASE
  1129. X/* delete an article number from a newsgroup, if it is there */
  1130. X
  1131. Xvoid
  1132. Xsubartnum(artnum,ngnam)
  1133. Xregister ART_NUM artnum;
  1134. Xchar *ngnam;
  1135. X{
  1136. X    register NG_NUM ngnum = find_ng(ngnam);
  1137. X    register char *s, *t;
  1138. X    register ART_NUM min, max;
  1139. X    char *mbuf;
  1140. X    int curlen;
  1141. X
  1142. X    if (!artnum)
  1143. X    return;
  1144. X    if (ngnum == nextrcline || !rcnums[ngnum])
  1145. X    return;                /* not found in newsrc? */
  1146. X#ifdef DEBUGGING
  1147. X    if (debug & DEB_XREF_MARKER) {
  1148. X    printf("%ld<-\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
  1149. X      rcline[ngnum] + rcnums[ngnum]) FLUSH;
  1150. X    }
  1151. X#endif
  1152. X    s = rcline[ngnum] + rcnums[ngnum];
  1153. X    while (*s == ' ') s++;        /* skip spaces */
  1154. X    
  1155. X    /* a little optimization, since it is almost always the last number */
  1156. X    
  1157. X    for (t=s; *t; t++) ;        /* find end of string */
  1158. X    curlen = t-rcline[ngnum];
  1159. X    for (t--; isdigit(*t); t--) ;    /* find previous delim */
  1160. X    if (*t == ',' && atol(t+1) == artnum) {
  1161. X    *t = '\0';
  1162. X    if (toread[ngnum] >= TR_NONE)
  1163. X        ++toread[ngnum];
  1164. X#ifdef DEBUGGING
  1165. X    if (debug & DEB_XREF_MARKER)
  1166. X        printf("%s%c %s\n",rcline[ngnum],rcchar[ngnum],s) FLUSH;
  1167. X#endif
  1168. X    return;
  1169. X    }
  1170. X
  1171. X    /* not the last number, oh well, we may need the length anyway */
  1172. X
  1173. X    while (isdigit(*s) && artnum >= (min = atol(s))) {
  1174. X                    /* while it might have been read */
  1175. X    for (t = s; isdigit(*t); t++) ;    /* skip number */
  1176. X    if (*t == '-') {        /* is it a range? */
  1177. X        t++;            /* skip to next number */
  1178. X        max = atol(t);
  1179. X        while (isdigit(*t)) t++;    /* skip second number */
  1180. X        if (artnum <= max) {
  1181. X                    /* it is in range => already read */
  1182. X        if (artnum == min) {
  1183. X            min++;
  1184. X            artnum = 0;
  1185. X        }
  1186. X        else if (artnum == max) {
  1187. X            max--;
  1188. X            artnum = 0;
  1189. X        }
  1190. X        *(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
  1191. X        mbuf = safemalloc((MEM_SIZE)(curlen + (artnum?15:2)));
  1192. X        *s = '\0';
  1193. X        strcpy(mbuf,rcline[ngnum]);    /* make new rc line */
  1194. X        s = mbuf + (s-rcline[ngnum]);
  1195. X                    /* point s into mbuf now */
  1196. X        if (artnum) {        /* split into two ranges? */
  1197. X            prange(s,min,artnum-1);
  1198. X            s += strlen(s);
  1199. X            *s++ = ',';
  1200. X            prange(s,artnum+1,max);
  1201. X        }
  1202. X        else            /* only one range */
  1203. X            prange(s,min,max);
  1204. X        s += strlen(s);
  1205. X        strcpy(s,t);        /* copy remainder over */
  1206. X#ifdef DEBUGGING
  1207. X        if (debug & DEB_XREF_MARKER) {
  1208. X            printf("%s\n",mbuf) FLUSH;
  1209. X        }
  1210. X#endif
  1211. X        free(rcline[ngnum]);
  1212. X        rcline[ngnum] = mbuf;    /* pull the switcheroo */
  1213. X        *(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
  1214. X                    /* wipe out : or ! */
  1215. X        if (toread[ngnum] >= TR_NONE)
  1216. X            ++toread[ngnum];
  1217. X        return;
  1218. X        }
  1219. X    }
  1220. X    else {
  1221. X        if (artnum == min) {    /* explicitly a read article? */
  1222. X        if (*t == ',')        /* pick a comma, any comma */
  1223. X            t++;
  1224. X        else if (s[-1] == ',')
  1225. X            s--;
  1226. X        else if (s[-2] == ',')    /* (in case of space) */
  1227. X            s -= 2;
  1228. X        strcpy(s,t);        /* no need to realloc */
  1229. X        if (toread[ngnum] >= TR_NONE)
  1230. X            ++toread[ngnum];
  1231. X#ifdef DEBUGGING
  1232. X        if (debug & DEB_XREF_MARKER) {
  1233. X            printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
  1234. X              rcline[ngnum] + rcnums[ngnum]) FLUSH;
  1235. X        }
  1236. X#endif
  1237. X        return;
  1238. X        }
  1239. X    }
  1240. X    while (*t && !isdigit(*t)) t++;    /* skip comma and any spaces */
  1241. X    s = t;
  1242. X    }
  1243. X}
  1244. X
  1245. Xvoid
  1246. Xprange(where,min,max)
  1247. Xchar *where;
  1248. XART_NUM min,max;
  1249. X{
  1250. X    if (min == max)
  1251. X    sprintf(where,"%ld",(long)min);
  1252. X    else
  1253. X    sprintf(where,"%ld-%ld",(long)min,(long)max);
  1254. X}
  1255. X#endif
  1256. X
  1257. X/* calculate the number of unread articles for a newsgroup */
  1258. X
  1259. Xvoid
  1260. Xset_toread(ngnum)
  1261. Xregister NG_NUM ngnum;
  1262. X{
  1263. X    register char *s, *c, *h;
  1264. X    char tmpbuf[64], *mybuf = tmpbuf;
  1265. X    char *nums;
  1266. X    int length;
  1267. X#ifdef CACHEFIRST
  1268. X    bool virgin_ng = (!abs1st[ngnum]);
  1269. X#endif
  1270. X    ART_NUM ngsize = getngsize(ngnum);
  1271. X    ART_NUM unread = ngsize;
  1272. X    ART_NUM newmax;
  1273. X
  1274. X#if defined(DEBUGGING) && !defined(USETHREADS)
  1275. X    ngmax[ngnum] = ngsize;        /* for checking out-of-range Xrefs */
  1276. X#endif
  1277. X    if (ngsize == TR_BOGUS) {
  1278. X    printf("Warning!  Bogus newsgroup: %s\n",rcline[ngnum]) FLUSH;
  1279. X    paranoid = TRUE;
  1280. X    toread[ngnum] = TR_BOGUS;
  1281. X    return;
  1282. X    }
  1283. X#ifdef CACHEFIRST
  1284. X    if (virgin_ng)
  1285. X#else
  1286. X    if (!toread[ngnum])
  1287. X#endif
  1288. X    {
  1289. X    sprintf(tmpbuf," 1-%ld",(long)ngsize);
  1290. X    if (strNE(tmpbuf,rcline[ngnum]+rcnums[ngnum]))
  1291. X        checkexpired(ngnum,ngsize);    /* this might realloc rcline */
  1292. X    }
  1293. X    nums = rcline[ngnum]+rcnums[ngnum];
  1294. X    length = strlen(nums);
  1295. X    if (length >= 60)
  1296. X    mybuf = safemalloc((MEM_SIZE)(length+5));
  1297. X    strcpy(mybuf,nums);
  1298. X    mybuf[length++] = ',';
  1299. X    mybuf[length] = '\0';
  1300. X    for (s = mybuf; isspace(*s); s++)
  1301. X        ;
  1302. X    for ( ; (c = index(s,',')) != Nullch ; s = ++c) {
  1303. X                    /* for each range */
  1304. X    *c = '\0';            /* keep index from running off */
  1305. X    if ((h = index(s,'-')) != Nullch)    /* find - in range, if any */
  1306. X        unread -= (newmax = atol(h+1)) - atol(s) + 1;
  1307. X    else if (newmax = atol(s))
  1308. X        unread--;        /* recalculate length */
  1309. X    if (newmax > ngsize) {    /* paranoia check */
  1310. X        unread = -1;
  1311. X        break;
  1312. X    }
  1313. X    }
  1314. X    if (unread >= 0)        /* reasonable number? */
  1315. X    toread[ngnum] = (ART_UNREAD)unread;
  1316. X                    /* remember how many are left */
  1317. X#ifdef USETHREADS
  1318. X    else if (unread >= -100) {
  1319. X    /* If mthreads is in the process of updating the database, it's possible
  1320. X    ** for the .thread file to be more up-to-date than the numbers in the
  1321. X    ** active file (caused by buffering).  If so, it's also possible for the
  1322. X    ** user to have read past the end of the group as we know it.  Assume
  1323. X    ** 100 articles is enough of a buffer to distinguish reset newsgroups.
  1324. X    */
  1325. X    toread[ngnum] = 0;
  1326. X    }
  1327. X#endif
  1328. X    else {                /* SOMEONE RESET THE NEWSGROUP!!! */
  1329. X    toread[ngnum] = (ART_UNREAD)ngsize;
  1330. X                    /* assume nothing carried over */
  1331. X    printf("Warning!  Somebody reset %s--assuming nothing read.\n",
  1332. X        rcline[ngnum]) FLUSH;
  1333. X    *(rcline[ngnum] + rcnums[ngnum]) = '\0';
  1334. X    paranoid = TRUE;        /* enough to make a guy paranoid */
  1335. X    }
  1336. X    if (mybuf != tmpbuf)
  1337. X    free(mybuf);
  1338. X    if (rcchar[ngnum] == NEGCHAR)
  1339. X    toread[ngnum] = TR_UNSUB;
  1340. X}
  1341. X
  1342. X/* make sure expired articles are marked as read */
  1343. X
  1344. Xvoid
  1345. Xcheckexpired(ngnum,ngsize)
  1346. Xregister NG_NUM ngnum;
  1347. XART_NUM ngsize;
  1348. X{
  1349. X    register ART_NUM a1st = getabsfirst(ngnum,ngsize);
  1350. X    register char *s, *t;
  1351. X    register ART_NUM num, lastnum = 0;
  1352. X    char *mbuf, *newnum;
  1353. X
  1354. X    if (a1st<=1)
  1355. X    return;
  1356. X#ifdef DEBUGGING
  1357. X    if (debug & DEB_XREF_MARKER) {
  1358. X    printf("1-%ld->\n%s%c%s\n",(long)(a1st-1),rcline[ngnum],rcchar[ngnum],
  1359. X      rcline[ngnum] + rcnums[ngnum]) FLUSH;
  1360. X    }
  1361. X#endif
  1362. X    for (s = rcline[ngnum] + rcnums[ngnum]; isspace(*s); s++);
  1363. X    while (*s && (num = atol(s)) <= a1st) {
  1364. X    while (isdigit(*s)) s++;
  1365. X    while (*s && !isdigit(*s)) s++;
  1366. X    lastnum = num;
  1367. X    }
  1368. X    if (*s) {
  1369. X    if (s[-1] == '-') {            /* landed in a range? */
  1370. X        if (lastnum != 1) {
  1371. X        if (3 + strlen(s) > strlen(rcline[ngnum]+rcnums[ngnum])) {
  1372. X            mbuf = safemalloc((MEM_SIZE)(rcnums[ngnum] + 3 +
  1373. X            strlen(s) + 1));
  1374. X            strcpy(mbuf, rcline[ngnum]);
  1375. X            sprintf(mbuf+rcnums[ngnum]," 1-%s",s);
  1376. X            free(rcline[ngnum]);
  1377. X            rcline[ngnum] = mbuf;
  1378. X        } else {
  1379. X            sprintf(rcline[ngnum]+rcnums[ngnum]," 1-%s",s);
  1380. X        }
  1381. X        }
  1382. X        goto ret;
  1383. X    }
  1384. X    }
  1385. X    /* s now points to what should follow first range */
  1386. X    if (s - rcline[ngnum] > rcnums[ngnum] + 10) 
  1387. X    mbuf = rcline[ngnum];
  1388. X    else {
  1389. X    mbuf = safemalloc((MEM_SIZE)(rcnums[ngnum] + strlen(s) + 10));
  1390. X    strcpy(mbuf,rcline[ngnum]);
  1391. X    }
  1392. X    newnum = t = mbuf+rcnums[ngnum];
  1393. X    sprintf(t," 1-%ld",(long)(a1st - (lastnum != a1st)));
  1394. X    if (*s) {
  1395. X    t += strlen(t);
  1396. X    *t++ = ',';
  1397. X    strcpy(t,s);
  1398. X    }
  1399. X    if (!checkflag && mbuf == rcline[ngnum]) {
  1400. X    rcline[ngnum] = saferealloc(rcline[ngnum],
  1401. X        (MEM_SIZE)(rcnums[ngnum] + strlen(newnum) + 1));
  1402. X    }
  1403. X    else {
  1404. X    if (!checkflag)
  1405. X        free(rcline[ngnum]);
  1406. X    rcline[ngnum] = mbuf;
  1407. X    }
  1408. X
  1409. Xret:;        /* semicolon in case DEBUGGING undefined */
  1410. X#ifdef DEBUGGING
  1411. X    if (debug & DEB_XREF_MARKER) {
  1412. X    printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
  1413. X      rcline[ngnum] + rcnums[ngnum]) FLUSH;
  1414. X    }
  1415. X#endif
  1416. X}
  1417. X
  1418. END_OF_FILE
  1419.   if test 13006 -ne `wc -c <'rcln.c'`; then
  1420.     echo shar: \"'rcln.c'\" unpacked with wrong size!
  1421.   fi
  1422.   # end of 'rcln.c'
  1423. fi
  1424. if test -f 'search.c' -a "${1}" != "-c" ; then 
  1425.   echo shar: Will not clobber existing file \"'search.c'\"
  1426. else
  1427.   echo shar: Extracting \"'search.c'\" \(13460 characters\)
  1428.   sed "s/^X//" >'search.c' <<'END_OF_FILE'
  1429. X/* $Header: search.c,v 4.3.2.2 90/03/22 23:05:31 sob Exp $
  1430. X *
  1431. X * $Log:    search.c,v $
  1432. X * Revision 4.3.2.2  90/03/22  23:05:31  sob
  1433. X * Fixes provided by Wayne Davison <drivax!davison>
  1434. X * 
  1435. X * Revision 4.3.2.1  90/03/17  17:46:29  sob
  1436. X * Added changes to insure that null search strings won't result in core dumps
  1437. X * on non-VAX computers.
  1438. X * 
  1439. X * Revision 4.3  85/05/01  11:50:16  lwall
  1440. X * Baseline for release with 4.3bsd.
  1441. X * 
  1442. X */
  1443. X
  1444. X/* string search routines */
  1445. X/*        Copyright (c) 1981,1980 James Gosling        */
  1446. X/* Modified Aug. 12, 1981 by Tom London to include regular expressions
  1447. X   as in ed.  RE stuff hacked over by jag to correct a few major problems,
  1448. X   mainly dealing with searching within the buffer rather than copying
  1449. X   each line to a separate array.  Newlines can now appear in RE's */
  1450. X
  1451. X/* Ripped to shreds and glued back together to make a search package,
  1452. X * July 6, 1984, by Larry Wall. (If it doesn't work, it's probably my fault.)
  1453. X * Changes include:
  1454. X *    Buffer, window, and mlisp stuff gone.
  1455. X *    Translation tables reduced to 1 table.
  1456. X *    Expression buffer is now dynamically allocated.
  1457. X *    Character classes now implemented with a bitmap.
  1458. X */
  1459. X
  1460. X#include "EXTERN.h"
  1461. X#include "common.h"
  1462. X#include "util.h"
  1463. X#include "INTERN.h"
  1464. X#include "search.h"
  1465. X
  1466. X#ifndef BITSPERBYTE
  1467. X#define BITSPERBYTE 8
  1468. X#endif
  1469. X
  1470. X#define BMAPSIZ (127 / BITSPERBYTE + 1)
  1471. X
  1472. X/* meta characters in the "compiled" form of a regular expression */
  1473. X#define    CBRA    2        /* \( -- begin bracket */
  1474. X#define    CCHR    4        /* a vanilla character */
  1475. X#define    CDOT    6        /* . -- match anything except a newline */
  1476. X#define    CCL    8        /* [...] -- character class */
  1477. X#define    NCCL    10        /* [^...] -- negated character class */
  1478. X#define    CDOL    12        /* $ -- matches the end of a line */
  1479. X#define    CEND    14        /* The end of the pattern */
  1480. X#define    CKET    16        /* \) -- close bracket */
  1481. X#define    CBACK    18        /* \N -- backreference to the Nth bracketed
  1482. X                   string */
  1483. X#define CIRC    20        /* ^ matches the beginning of a line */
  1484. X
  1485. X#define WORD    32        /* matches word character \w */
  1486. X#define NWORD    34        /* matches non-word characer \W */
  1487. X#define WBOUND    36        /* matches word boundary \b */
  1488. X#define NWBOUND    38        /* matches non-(word boundary) \B */
  1489. X#define    STAR    01        /* * -- Kleene star, repeats the previous
  1490. X                   REas many times as possible; the value
  1491. X                   ORs with the other operator types */
  1492. X#define ASCSIZ 0200
  1493. Xtypedef char    TRANSTABLE[ASCSIZ];
  1494. X
  1495. Xstatic    TRANSTABLE trans = {
  1496. X0000,0001,0002,0003,0004,0005,0006,0007,
  1497. X0010,0011,0012,0013,0014,0015,0016,0017,
  1498. X0020,0021,0022,0023,0024,0025,0026,0027,
  1499. X0030,0031,0032,0033,0034,0035,0036,0037,
  1500. X0040,0041,0042,0043,0044,0045,0046,0047,
  1501. X0050,0051,0052,0053,0054,0055,0056,0057,
  1502. X0060,0061,0062,0063,0064,0065,0066,0067,
  1503. X0070,0071,0072,0073,0074,0075,0076,0077,
  1504. X0100,0101,0102,0103,0104,0105,0106,0107,
  1505. X0110,0111,0112,0113,0114,0115,0116,0117,
  1506. X0120,0121,0122,0123,0124,0125,0126,0127,
  1507. X0130,0131,0132,0133,0134,0135,0136,0137,
  1508. X0140,0141,0142,0143,0144,0145,0146,0147,
  1509. X0150,0151,0152,0153,0154,0155,0156,0157,
  1510. X0160,0161,0162,0163,0164,0165,0166,0167,
  1511. X0170,0171,0172,0173,0174,0175,0176,0177,
  1512. X};
  1513. Xstatic bool folding = FALSE;
  1514. X
  1515. Xstatic int err;
  1516. Xstatic char *FirstCharacter;
  1517. X
  1518. Xvoid
  1519. Xsearch_init()
  1520. X{
  1521. X#ifdef UNDEF
  1522. X    register int    i;
  1523. X    
  1524. X    for (i = 0; i < ASCSIZ; i++)
  1525. X    trans[i] = i;
  1526. X#else
  1527. X    ;
  1528. X#endif
  1529. X}
  1530. X
  1531. Xvoid
  1532. Xinit_compex(compex)
  1533. Xregister COMPEX *compex;
  1534. X{
  1535. X    /* the following must start off zeroed */
  1536. X
  1537. X    compex->eblen = 0;
  1538. X    compex->brastr = Nullch;
  1539. X}
  1540. X
  1541. Xvoid
  1542. Xfree_compex(compex)
  1543. Xregister COMPEX *compex;
  1544. X{
  1545. X    if (compex->eblen) {
  1546. X    free(compex->expbuf);
  1547. X    compex->eblen = 0;
  1548. X    }
  1549. X    if (compex->brastr) {
  1550. X    free(compex->brastr);
  1551. X    compex->brastr = Nullch;
  1552. X    }
  1553. X}
  1554. X
  1555. Xstatic char *gbr_str = Nullch;
  1556. Xstatic int gbr_siz = 0;
  1557. X
  1558. Xchar *
  1559. Xgetbracket(compex,n)
  1560. Xregister COMPEX *compex;
  1561. Xint n;
  1562. X{
  1563. X    int length = compex->braelist[n] - compex->braslist[n];
  1564. X
  1565. X    if (!compex->nbra || n > compex->nbra || !compex->braelist[n] || length<0)
  1566. X    return nullstr;
  1567. X    growstr(&gbr_str, &gbr_siz, length+1);
  1568. X    safecpy(gbr_str, compex->braslist[n], length+1);
  1569. X    return gbr_str;
  1570. X}
  1571. X
  1572. Xvoid
  1573. Xcase_fold(which)
  1574. Xint which;
  1575. X{
  1576. X    register int i;
  1577. X
  1578. X    if (which != folding) {
  1579. X    if (which) {
  1580. X        for (i = 'A'; i <= 'Z'; i++)
  1581. X        trans[i] = tolower(i);
  1582. X    }
  1583. X    else {
  1584. X        for (i = 'A'; i <= 'Z'; i++)
  1585. X        trans[i] = i;
  1586. X    }
  1587. X    folding = which;
  1588. X    }
  1589. X}
  1590. X
  1591. X/* Compile the given regular expression into a [secret] internal format */
  1592. X
  1593. Xchar *
  1594. Xcompile (compex, strp, RE, fold)
  1595. Xregister COMPEX *compex;
  1596. Xregister char   *strp;
  1597. Xint RE;
  1598. Xint fold;
  1599. X{
  1600. X    register int c;
  1601. X    register char  *ep;
  1602. X    char   *lastep;
  1603. X    char    bracket[NBRA],
  1604. X       *bracketp;
  1605. X    char **alt = compex->alternatives;
  1606. X    char *retmes = "Badly formed search string";
  1607. X    case_fold(compex->do_folding = fold);
  1608. X    if (!compex->eblen) {
  1609. X    compex->expbuf = safemalloc(84);
  1610. X    compex->eblen = 80;
  1611. X    }
  1612. X    ep = compex->expbuf;        /* point at expression buffer */
  1613. X    *alt++ = ep;            /* first alternative starts here */
  1614. X    bracketp = bracket;            /* first bracket goes here */
  1615. X    if (*strp == 0) {            /* nothing to compile? */
  1616. X    if (*ep == 0)            /* nothing there yet? */
  1617. X        return "Null search string";
  1618. X    return Nullch;            /* just keep old expression */
  1619. X    }
  1620. X    compex->nbra = 0;            /* no brackets yet */
  1621. X    lastep = 0;
  1622. X    for (;;) {
  1623. X    if (ep - compex->expbuf >= compex->eblen)
  1624. X        grow_eb(compex);
  1625. X    c = *strp++;            /* fetch next char of pattern */
  1626. X    if (c == 0) {            /* end of pattern? */
  1627. X        if (bracketp != bracket) {    /* balanced brackets? */
  1628. X#ifdef VERBOSE
  1629. X        retmes = "Unbalanced parens";
  1630. X#endif
  1631. X        goto cerror;
  1632. X        }
  1633. X        *ep++ = CEND;        /* terminate expression */
  1634. X        *alt++ = 0;            /* terminal alternative list */
  1635. X        /*
  1636. X        compex->eblen = ep - compex->expbuf + 1;
  1637. X        compex->expbuf = saferealloc(compex->expbuf,compex->eblen+4); */
  1638. X        return Nullch;        /* return success */
  1639. X    }
  1640. X    if (c != '*')
  1641. X        lastep = ep;
  1642. X    if (!RE) {            /* just a normal search string? */
  1643. X        *ep++ = CCHR;        /* everything is a normal char */
  1644. X        *ep++ = c;
  1645. X    }
  1646. X    else                /* it is a regular expression */
  1647. X        switch (c) {
  1648. X        case '\\':        /* meta something */
  1649. X            switch (c = *strp++) {
  1650. X            case '(':
  1651. X            if (compex->nbra >= NBRA) {
  1652. X#ifdef VERBOSE
  1653. X                retmes = "Too many parens";
  1654. X#endif
  1655. X                goto cerror;
  1656. X            }
  1657. X            *bracketp++ = ++compex->nbra;
  1658. X            *ep++ = CBRA;
  1659. X            *ep++ = compex->nbra;
  1660. X            break;
  1661. X            case '|':
  1662. X            if (bracketp>bracket) {
  1663. X#ifdef VERBOSE
  1664. X                retmes = "No \\| in parens";    /* Alas! */
  1665. X#endif
  1666. X                goto cerror;
  1667. X            }
  1668. X            *ep++ = CEND;
  1669. X            *alt++ = ep;
  1670. X            break;
  1671. X            case ')':
  1672. X            if (bracketp <= bracket) {
  1673. X#ifdef VERBOSE
  1674. X                retmes = "Unmatched right paren";
  1675. X#endif
  1676. X                goto cerror;
  1677. X            }
  1678. X            *ep++ = CKET;
  1679. X            *ep++ = *--bracketp;
  1680. X            break;
  1681. X            case 'w':
  1682. X            *ep++ = WORD;
  1683. X            break;
  1684. X            case 'W':
  1685. X            *ep++ = NWORD;
  1686. X            break;
  1687. X            case 'b':
  1688. X            *ep++ = WBOUND;
  1689. X            break;
  1690. X            case 'B':
  1691. X            *ep++ = NWBOUND;
  1692. X            break;
  1693. X            case '0': case '1': case '2': case '3': case '4':
  1694. X            case '5': case '6': case '7': case '8': case '9':
  1695. X            *ep++ = CBACK;
  1696. X            *ep++ = c - '0';
  1697. X            break;
  1698. X            default:
  1699. X            *ep++ = CCHR;
  1700. X            if (c == '\0')
  1701. X                goto cerror;
  1702. X            *ep++ = c;
  1703. X            break;
  1704. X            }
  1705. X            break;
  1706. X        case '.':
  1707. X            *ep++ = CDOT;
  1708. X            continue;
  1709. X        case '*':
  1710. X            if (lastep == 0 || *lastep == CBRA || *lastep == CKET
  1711. X            || *lastep == CIRC
  1712. X            || (*lastep&STAR)|| *lastep>NWORD)
  1713. X            goto defchar;
  1714. X            *lastep |= STAR;
  1715. X            continue;
  1716. X        case '^':
  1717. X            if (ep != compex->expbuf && ep[-1] != CEND)
  1718. X            goto defchar;
  1719. X            *ep++ = CIRC;
  1720. X            continue;
  1721. X        case '$':
  1722. X            if (*strp != 0 && (*strp != '\\' || strp[1] != '|'))
  1723. X            goto defchar;
  1724. X            *ep++ = CDOL;
  1725. X            continue;
  1726. X        case '[': {        /* character class */
  1727. X            register int i;
  1728. X            
  1729. X            if (ep - compex->expbuf >= compex->eblen - BMAPSIZ)
  1730. X            grow_eb(compex);    /* reserve bitmap */
  1731. X            for (i = BMAPSIZ; i; --i)
  1732. X            ep[i] = 0;
  1733. X            
  1734. X            if ((c = *strp++) == '^') {
  1735. X            c = *strp++;
  1736. X            *ep++ = NCCL;    /* negated */
  1737. X            }
  1738. X            else
  1739. X            *ep++ = CCL;    /* normal */
  1740. X            
  1741. X            i = 0;        /* remember oldchar */
  1742. X            do {
  1743. X            if (c == '\0') {
  1744. X#ifdef VERBOSE
  1745. X                retmes = "Missing ]";
  1746. X#endif
  1747. X                goto cerror;
  1748. X            }
  1749. X            if (*strp == '-' && *(++strp))
  1750. X                i = *strp++;
  1751. X            else
  1752. X                i = c;
  1753. X            while (c <= i) {
  1754. X                ep[c / BITSPERBYTE] |= 1 << (c % BITSPERBYTE);
  1755. X                if (fold && isalpha(c))
  1756. X                ep[(c ^ 32) / BITSPERBYTE] |=
  1757. X                    1 << ((c ^ 32) % BITSPERBYTE);
  1758. X                    /* set the other bit too */
  1759. X                c++;
  1760. X            }
  1761. X            } while ((c = *strp++) != ']');
  1762. X            ep += BMAPSIZ;
  1763. X            continue;
  1764. X        }
  1765. X        defchar:
  1766. X        default:
  1767. X            *ep++ = CCHR;
  1768. X            *ep++ = c;
  1769. X        }
  1770. X    }
  1771. Xcerror:
  1772. X    compex->expbuf[0] = 0;
  1773. X    compex->nbra = 0;
  1774. X    return retmes;
  1775. X}
  1776. X
  1777. Xvoid
  1778. Xgrow_eb(compex)
  1779. Xregister COMPEX *compex;
  1780. X{
  1781. X    compex->eblen += 80;
  1782. X    compex->expbuf = saferealloc(compex->expbuf, (MEM_SIZE)compex->eblen + 4);
  1783. X}
  1784. X
  1785. Xchar *
  1786. Xexecute (compex, addr)
  1787. Xregister COMPEX *compex;
  1788. Xchar *addr;
  1789. X{
  1790. X    register char *p1 = addr;
  1791. X    register char *trt = trans;
  1792. X    register int c;
  1793. X    if (addr == Nullch || compex->expbuf == Nullch)
  1794. X    return Nullch;
  1795. X    if (compex->nbra) {            /* any brackets? */
  1796. X    for (c = 0; c <= compex->nbra; c++)
  1797. X        compex->braslist[c] = compex->braelist[c] = Nullch;
  1798. X    if (compex->brastr)
  1799. X        free(compex->brastr);
  1800. X    compex->brastr = savestr(p1);    /* in case p1 is not static */
  1801. X    p1 = compex->brastr;        /* ! */
  1802. X    }
  1803. X    case_fold(compex->do_folding);    /* make sure table is correct */
  1804. X    FirstCharacter = p1;        /* for ^ tests */
  1805. X    if (compex->expbuf[0] == CCHR && !compex->alternatives[1]) {
  1806. X    c = trt[compex->expbuf[1]];    /* fast check for first character */
  1807. X    do {
  1808. X        if (trt[*p1] == c && advance (compex, p1, compex->expbuf))
  1809. X        return p1;
  1810. X        p1++;
  1811. X    } while (*p1 && !err);
  1812. X    return Nullch;
  1813. X    }
  1814. X    else {            /* regular algorithm */
  1815. X    do {
  1816. X        register char **alt = compex->alternatives;
  1817. X        while (*alt) {
  1818. X        if (advance (compex, p1, *alt++))
  1819. X            return p1;
  1820. X        }
  1821. X        p1++;
  1822. X    } while (*p1 && !err);
  1823. X    return Nullch;
  1824. X    }
  1825. X}
  1826. X/* advance the match of the regular expression starting at ep along the
  1827. X   string lp, simulates an NDFSA */
  1828. Xbool
  1829. Xadvance (compex, lp, ep)
  1830. Xregister COMPEX *compex;
  1831. Xregister char *ep;
  1832. Xregister char *lp;
  1833. X{
  1834. X    register char *curlp;
  1835. X    register char *trt = trans;
  1836. X    register int i;
  1837. X    while ((*ep & STAR) || *lp || *ep == CIRC || *ep == CKET)
  1838. X    switch (*ep++) {
  1839. X        case CCHR:
  1840. X        if (trt[*ep++] != trt[*lp]) return FALSE;
  1841. X        lp++;
  1842. X        continue;
  1843. X        case CDOT:
  1844. X        if (*lp == '\n') return FALSE;
  1845. X        lp++;
  1846. X        continue;
  1847. X        case CDOL:
  1848. X        if (!*lp || *lp == '\n')
  1849. X            continue;
  1850. X        return FALSE;
  1851. X        case CIRC:
  1852. X        if (lp == FirstCharacter || lp[-1]=='\n')
  1853. X            continue;
  1854. X        return FALSE;
  1855. X        case WORD:
  1856. X        if (isalnum(*lp)) {
  1857. X            lp++;
  1858. X            continue;
  1859. X        }
  1860. X        return FALSE;
  1861. X        case NWORD:
  1862. X        if (!isalnum(*lp)) {
  1863. X            lp++;
  1864. X            continue;
  1865. X        }
  1866. X        return FALSE;
  1867. X        case WBOUND:
  1868. X        if ((lp == FirstCharacter || !isalnum(lp[-1])) !=
  1869. X            (!*lp || !isalnum(*lp)) )
  1870. X            continue;
  1871. X        return FALSE;
  1872. X        case NWBOUND:
  1873. X        if ((lp == FirstCharacter || !isalnum(lp[-1])) ==
  1874. X            (!*lp || !isalnum(*lp)))
  1875. X            continue;
  1876. X        return FALSE;
  1877. X        case CEND:
  1878. X        return TRUE;
  1879. X        case CCL:
  1880. X        if (cclass (ep, *lp, 1)) {
  1881. X            ep += BMAPSIZ;
  1882. X            lp++;
  1883. X            continue;
  1884. X        }
  1885. X        return FALSE;
  1886. X        case NCCL:
  1887. X        if (cclass (ep, *lp, 0)) {
  1888. X            ep += BMAPSIZ;
  1889. X            lp++;
  1890. X            continue;
  1891. X        }
  1892. X        return FALSE;
  1893. X        case CBRA:
  1894. X        compex->braslist[*ep++] = lp;
  1895. X        continue;
  1896. X        case CKET:
  1897. X        i = *ep++;
  1898. X        compex->braelist[i] = lp;
  1899. X        compex->braelist[0] = lp;
  1900. X        compex->braslist[0] = compex->braslist[i];
  1901. X        continue;
  1902. X        case CBACK:
  1903. X        if (compex->braelist[i = *ep++] == 0) {
  1904. X            fputs("bad braces\n",stdout) FLUSH;
  1905. X            err = TRUE;
  1906. X            return FALSE;
  1907. X        }
  1908. X        if (backref (compex, i, lp)) {
  1909. X            lp += compex->braelist[i] - compex->braslist[i];
  1910. X            continue;
  1911. X        }
  1912. X        return FALSE;
  1913. X        case CBACK | STAR:
  1914. X        if (compex->braelist[i = *ep++] == 0) {
  1915. X            fputs("bad braces\n",stdout) FLUSH;
  1916. X            err = TRUE;
  1917. X            return FALSE;
  1918. X        }
  1919. X        curlp = lp;
  1920. X        while (backref (compex, i, lp)) {
  1921. X            lp += compex->braelist[i] - compex->braslist[i];
  1922. X        }
  1923. X        while (lp >= curlp) {
  1924. X            if (advance (compex, lp, ep))
  1925. X            return TRUE;
  1926. X            lp -= compex->braelist[i] - compex->braslist[i];
  1927. X        }
  1928. X        continue;
  1929. X        case CDOT | STAR:
  1930. X        curlp = lp;
  1931. X        while (*lp++ && lp[-1] != '\n');
  1932. X        goto star;
  1933. X        case WORD | STAR:
  1934. X        curlp = lp;
  1935. X        while (*lp++ && isalnum(lp[-1]));
  1936. X        goto star;
  1937. X        case NWORD | STAR:
  1938. X        curlp = lp;
  1939. X        while (*lp++ && !isalnum(lp[-1]));
  1940. X        goto star;
  1941. X        case CCHR | STAR:
  1942. X        curlp = lp;
  1943. X        while (*lp++ && trt[lp[-1]] == trt[*ep]);
  1944. X        ep++;
  1945. X        goto star;
  1946. X        case CCL | STAR:
  1947. X        case NCCL | STAR:
  1948. X        curlp = lp;
  1949. X        while (*lp++ && cclass (ep, lp[-1], ep[-1] == (CCL | STAR)));
  1950. X        ep += BMAPSIZ;
  1951. X        goto star;
  1952. X    star:
  1953. X        do {
  1954. X            lp--;
  1955. X            if (advance (compex, lp, ep))
  1956. X            return TRUE;
  1957. X        } while (lp > curlp);
  1958. X        return FALSE;
  1959. X        default:
  1960. X        fputs("Badly compiled pattern\n",stdout) FLUSH;
  1961. X        err = TRUE;
  1962. X        return -1;
  1963. X    }
  1964. X    if (*ep == CEND || *ep == CDOL) {
  1965. X        return TRUE;
  1966. X    }
  1967. X    return FALSE;
  1968. X}
  1969. Xbool
  1970. Xbackref (compex, i, lp)
  1971. Xregister COMPEX *compex;
  1972. Xregister int i;
  1973. Xregister char *lp;
  1974. X{
  1975. X    register char *bp;
  1976. X    bp = compex->braslist[i];
  1977. X    while (*lp && *bp == *lp) {
  1978. X    bp++;
  1979. X    lp++;
  1980. X    if (bp >= compex->braelist[i])
  1981. X        return TRUE;
  1982. X    }
  1983. X    return FALSE;
  1984. X}
  1985. X
  1986. Xbool
  1987. Xcclass (set, c, af)
  1988. Xregister char  *set;
  1989. Xregister int c;
  1990. X{
  1991. X    c &= 0177;
  1992. X#if BITSPERBYTE == 8
  1993. X    if (set[c >> 3] & 1 << (c & 7))
  1994. X#else
  1995. X    if (set[c / BITSPERBYTE] & 1 << (c % BITSPERBYTE))
  1996. X#endif
  1997. X    return af;
  1998. X    return !af;
  1999. X}
  2000. END_OF_FILE
  2001.   if test 13460 -ne `wc -c <'search.c'`; then
  2002.     echo shar: \"'search.c'\" unpacked with wrong size!
  2003.   fi
  2004.   # end of 'search.c'
  2005. fi
  2006. if test -f 'sw.c' -a "${1}" != "-c" ; then 
  2007.   echo shar: Will not clobber existing file \"'sw.c'\"
  2008. else
  2009.   echo shar: Extracting \"'sw.c'\" \(11791 characters\)
  2010.   sed "s/^X//" >'sw.c' <<'END_OF_FILE'
  2011. X/* $Header: sw.c,v 4.3.3.2 91/01/16 03:37:38 davison Trn $
  2012. X *
  2013. X * $Log:    sw.c,v $
  2014. X * Revision 4.3.3.2  91/01/16  03:37:38  davison
  2015. X * Integrated rn patches 48-54.
  2016. X * 
  2017. X * Revision 4.3.3.1  90/06/20  22:40:11  davison
  2018. X * Initial Trn Release
  2019. X * 
  2020. X * Revision 4.3.2.4  90/11/22  16:09:19  sob
  2021. X * Added changes to accomodate pickly C preprocessors
  2022. X * 
  2023. X * Revision 4.3.2.3  90/05/08  22:06:00  sob
  2024. X * Added quick startup (-q) flag.
  2025. X * 
  2026. X * Revision 4.3.2.2  90/03/22  23:05:34  sob
  2027. X * Fixes provided by Wayne Davison <drivax!davison>
  2028. X * 
  2029. X * Revision 4.3.2.1  89/12/09  00:52:40  sob
  2030. X * Now handles SIGWINCH correctly.
  2031. X * 
  2032. X * Revision 4.3.1.2  85/05/21  13:36:23  lwall
  2033. X * Sped up "rn -c" by not doing unnecessary initialization.
  2034. X * 
  2035. X * Revision 4.3.1.1  85/05/10  11:40:38  lwall
  2036. X * Branch for patches.
  2037. X * 
  2038. X * Revision 4.3  85/05/01  11:50:54  lwall
  2039. X * Baseline for release with 4.3bsd.
  2040. X * 
  2041. X */
  2042. X
  2043. X#include "EXTERN.h"
  2044. X#include "common.h"
  2045. X#include "util.h"
  2046. X#include "head.h"
  2047. X#include "only.h"
  2048. X#include "term.h"
  2049. X#include "ng.h"
  2050. X#include "intrp.h"
  2051. X#include "INTERN.h"
  2052. X#include "sw.h"
  2053. X
  2054. Xvoid
  2055. Xsw_init(argc,argv,tcbufptr)
  2056. Xint argc;
  2057. Xchar *argv[];
  2058. Xchar **tcbufptr;
  2059. X{
  2060. X    register int i;
  2061. X
  2062. X    if (argc >= 2 && strEQ(argv[1],"-c"))
  2063. X    checkflag=TRUE;            /* so we can optimize for -c */
  2064. X    interp(*tcbufptr,1024,GLOBINIT);
  2065. X    sw_file(tcbufptr,FALSE);
  2066. X    safecpy(*tcbufptr,getenv("RNINIT"),1024);
  2067. X    if (**tcbufptr) {
  2068. X    if (**tcbufptr == '/') {
  2069. X        sw_file(tcbufptr,TRUE);
  2070. X    }
  2071. X    else
  2072. X        sw_list(*tcbufptr);
  2073. X    }
  2074. X
  2075. X    for (i = 1; i < argc; i++)
  2076. X    decode_switch(argv[i]);
  2077. X}
  2078. X
  2079. Xvoid
  2080. Xsw_file(tcbufptr,bleat)
  2081. Xchar **tcbufptr;
  2082. Xbool bleat;
  2083. X{
  2084. X    int initfd = open(*tcbufptr,0);
  2085. X    
  2086. X    if (initfd >= 0) {
  2087. X    fstat(initfd,&filestat);
  2088. X    if (filestat.st_size > 1024)
  2089. X        *tcbufptr = saferealloc(*tcbufptr,(MEM_SIZE)filestat.st_size);
  2090. X    if (filestat.st_size) {
  2091. X        read(initfd,*tcbufptr,(int)filestat.st_size);
  2092. X        (*tcbufptr)[filestat.st_size-1] = '\0';
  2093. X                /* wipe out last newline */
  2094. X        sw_list(*tcbufptr);
  2095. X    }
  2096. X    else
  2097. X        **tcbufptr = '\0';
  2098. X    close(initfd);
  2099. X    }
  2100. X    else {
  2101. X    if (bleat)
  2102. X        printf(cantopen,*tcbufptr) FLUSH;
  2103. X    **tcbufptr = '\0';
  2104. X    }
  2105. X}
  2106. X
  2107. X/* decode a list of space separated switches */
  2108. X
  2109. Xvoid
  2110. Xsw_list(swlist)
  2111. Xchar *swlist;
  2112. X{
  2113. X    char *tmplist = safemalloc((MEM_SIZE) strlen(swlist) + 2);
  2114. X                    /* semi-automatic string */
  2115. X    register char *p, inquote = 0;
  2116. X
  2117. X    strcpy(tmplist,swlist);
  2118. X    for (p=tmplist; isspace(*p); p++) ;    /* skip any initial spaces */
  2119. X    while (*p) {            /* "String, or nothing" */
  2120. X    if (!inquote && isspace(*p)) {    /* word delimiter? */
  2121. X        *p++ = '\0';        /* chop here */
  2122. X        while (isspace(*p))        /* these will be ignored later */
  2123. X        p++;
  2124. X    }
  2125. X    else if (inquote == *p) {
  2126. X        strcpy(p,p+1);        /* delete trailing quote */
  2127. X        inquote = 0;        /* no longer quoting */
  2128. X    }
  2129. X    else if (!inquote && *p == '"' || *p == '\'') {
  2130. X                    /* OK, I know when I am not wanted */
  2131. X        inquote = *p;        /* remember single or double */
  2132. X        strcpy(p,p+1);        /* delete the quote */
  2133. X    }                /* (crude, but effective) */
  2134. X    else if (*p == '\\') {        /* quoted something? */
  2135. X        if (p[1] == '\n')        /* newline? */
  2136. X        strcpy(p,p+2);        /* "I didn't see anything" */
  2137. X        else {
  2138. X        strcpy(p,p+1);        /* delete the backwhack */
  2139. X        p++;            /* leave the whatever alone */
  2140. X        }
  2141. X    }
  2142. X    else
  2143. X        p++;            /* normal char, leave it alone */
  2144. X    }
  2145. X    *++p = '\0';            /* put an extra null on the end */
  2146. X    if (inquote)
  2147. X    printf("Unmatched %c in switch\n",inquote) FLUSH;
  2148. X    for (p = tmplist; *p; /* p += strlen(p)+1 */ ) {
  2149. X    decode_switch(p);
  2150. X    while (*p++) ;            /* point at null + 1 */
  2151. X    }
  2152. X    free(tmplist);            /* this oughta be in Ada */
  2153. X}
  2154. X
  2155. X/* decode a single switch */
  2156. X
  2157. Xvoid
  2158. Xdecode_switch(s)
  2159. Xregister char *s;
  2160. X{
  2161. X    while (isspace(*s))            /* ignore leading spaces */
  2162. X    s++;
  2163. X#ifdef DEBUGGING
  2164. X    if (debug)
  2165. X    printf("Switch: %s\n",s) FLUSH;
  2166. X#endif
  2167. X    if (*s != '-' && *s != '+') {    /* newsgroup pattern */
  2168. X    setngtodo(s);
  2169. X    }
  2170. X    else {                /* normal switch */
  2171. X    bool upordown = *s == '-' ? TRUE : FALSE;
  2172. X    char tmpbuf[LBUFLEN];
  2173. X
  2174. X    s++;
  2175. X    switch (*s) {
  2176. X#ifdef TERMMOD
  2177. X    case '=': {
  2178. X        char *beg = s+1;
  2179. X
  2180. X        while (*s && *s != '-' && *s != '+') s++;
  2181. X        cpytill(tmpbuf,beg,*s);
  2182. X        if (upordown ? strEQ(getenv("TERM"),tmpbuf)
  2183. X                 : strNE(getenv("TERM"),tmpbuf) ) {
  2184. X        decode_switch(s);
  2185. X        }
  2186. X        break;
  2187. X    }
  2188. X#endif
  2189. X#ifdef BAUDMOD
  2190. X    case '0': case '1': case '2': case '3': case '4':
  2191. X    case '5': case '6': case '7': case '8': case '9':
  2192. X        if (upordown ? (just_a_sec*10 <= atoi(s))
  2193. X                 : (just_a_sec*10 >= atoi(s)) ) {
  2194. X        while (isdigit(*s)) s++;
  2195. X        decode_switch(s);
  2196. X        }
  2197. X        break;
  2198. X#endif
  2199. X    case '/':
  2200. X        if (checkflag)
  2201. X        break;
  2202. X#ifdef SETENV
  2203. X        setenv("SAVEDIR",  upordown ? "%p/%c" : "%p" );
  2204. X        setenv("SAVENAME", upordown ? "%a"    : "%^C");
  2205. X#else
  2206. X        notincl("-/");
  2207. X#endif
  2208. X        break;
  2209. X    case 'c':
  2210. X        checkflag = upordown;
  2211. X        break;
  2212. X    case 'C':
  2213. X        s++;
  2214. X        if (*s == '=') s++;
  2215. X        docheckwhen = atoi(s);
  2216. X        break;
  2217. X    case 'd': {
  2218. X        if (checkflag)
  2219. X        break;
  2220. X        s++;
  2221. X        if (*s == '=') s++;
  2222. X        if (cwd) {
  2223. X        chdir(cwd);
  2224. X        free(cwd);
  2225. X        }
  2226. X        cwd = savestr(s);
  2227. X        break;
  2228. X    }
  2229. X#ifdef DEBUGGING
  2230. X    case 'D':
  2231. X        s++;
  2232. X        if (*s == '=') s++;
  2233. X        if (*s)
  2234. X        if (upordown)
  2235. X            debug |= atoi(s);
  2236. X        else
  2237. X            debug &= ~atoi(s);
  2238. X        else
  2239. X        if (upordown)
  2240. X            debug |= 1;
  2241. X        else
  2242. X            debug = 0;
  2243. X        break;
  2244. X#endif
  2245. X    case 'e':
  2246. X        erase_screen = upordown;
  2247. X        break;
  2248. X    case 'E':
  2249. X#ifdef SETENV
  2250. X        s++;
  2251. X        if (*s == '=')
  2252. X        s++;
  2253. X        strcpy(tmpbuf,s);
  2254. X        s = index(tmpbuf,'=');
  2255. X        if (s) {
  2256. X        *s++ = '\0';
  2257. X        setenv(tmpbuf,s);
  2258. X        }
  2259. X        else
  2260. X        setenv(tmpbuf,nullstr);
  2261. X#else
  2262. X        notincl("-E");
  2263. X#endif
  2264. X        break;
  2265. X    case 'F':
  2266. X        s++;
  2267. X        indstr = savestr(s);
  2268. X        break;
  2269. X#ifdef INNERSEARCH
  2270. X    case 'g':
  2271. X        gline = atoi(s+1)-1;
  2272. X        break;
  2273. X#endif
  2274. X    case 'H':
  2275. X    case 'h': {
  2276. X        register int len, i;
  2277. X        char *t;
  2278. X        int flag = (*s == 'h' ? HT_HIDE : HT_MAGIC);
  2279. X        
  2280. X        if (checkflag)
  2281. X        break;
  2282. X        s++;
  2283. X        len = strlen(s);
  2284. X        for (t=s; *t; t++)
  2285. X        if (isupper(*t))
  2286. X           *t = tolower(*t);
  2287. X        for (i=HEAD_FIRST; i<HEAD_LAST; i++)
  2288. X        if (!len || strnEQ(s,htype[i].ht_name,len))
  2289. X            if (upordown)
  2290. X            htype[i].ht_flags |= flag;
  2291. X            else
  2292. X            htype[i].ht_flags &= ~flag;
  2293. X        break;
  2294. X    }
  2295. X    case 'i':
  2296. X        s++;
  2297. X        if (*s == '=') s++;
  2298. X        initlines = atoi(s);
  2299. X        initlines_specified = TRUE;
  2300. X        break;
  2301. X    case 'l':
  2302. X        muck_up_clear = upordown;
  2303. X        break;
  2304. X    case 'L':
  2305. X#ifdef CLEAREOL
  2306. X        can_home_clear = upordown;
  2307. X#else
  2308. X        notincl("-L");
  2309. X#endif
  2310. X        break;
  2311. X    case 'M':
  2312. X        mbox_always = upordown;
  2313. X        break;
  2314. X    case 'm':
  2315. X        s++;
  2316. X        if (*s == '=') s++;
  2317. X        if (!upordown)
  2318. X        marking = NOMARKING;
  2319. X        else if (*s == 'u')
  2320. X        marking = UNDERLINE;
  2321. X        else {
  2322. X        marking = STANDOUT;
  2323. X        }
  2324. X        break;
  2325. X    case 'N':
  2326. X        norm_always = upordown;
  2327. X        break;
  2328. X#ifdef VERBOSE
  2329. X    case 'n':
  2330. X        fputs("This isn't readnews.  Don't use -n.\n\n",stdout) FLUSH;
  2331. X        break;
  2332. X#endif
  2333. X    case 'r':
  2334. X        findlast = upordown;
  2335. X        break;
  2336. X    case 's':
  2337. X        s++;
  2338. X        if (*s == '=') s++;
  2339. X        if (*s) {
  2340. X        countdown = atoi(s);
  2341. X        suppress_cn = FALSE;
  2342. X        }
  2343. X        else {
  2344. X        if (!upordown)
  2345. X            countdown = 5;
  2346. X        suppress_cn = upordown;
  2347. X        }
  2348. X        break;
  2349. X    case 'S':
  2350. X#ifdef ARTSEARCH
  2351. X        s++;
  2352. X        if (*s == '=') s++;
  2353. X        if (*s)
  2354. X        scanon = atoi(s);
  2355. X        else
  2356. X        scanon = upordown*3;
  2357. X#else
  2358. X        notincl("-S");
  2359. X#endif
  2360. X        break;
  2361. X    case 't':
  2362. X#ifdef VERBOSE
  2363. X#ifdef TERSE
  2364. X        verbose = !upordown;
  2365. X#else
  2366. X        notincl("+t");
  2367. X#endif
  2368. X#else
  2369. X        notincl("+t");
  2370. X#endif
  2371. X        break;
  2372. X    case 'T':
  2373. X        typeahead = upordown;
  2374. X        break;
  2375. X    case 'v':
  2376. X#ifdef VERIFY
  2377. X        verify = upordown;
  2378. X#else
  2379. X        notincl("-v");
  2380. X#endif
  2381. X        break;
  2382. X    case 'x':
  2383. X#ifdef USETHREADS
  2384. X        s++;
  2385. X        if (*s == '=') s++;
  2386. X        if (*s <= '9' && *s >= '0') {
  2387. X        if ((max_tree_lines = atoi(s)) > 11)
  2388. X            max_tree_lines = 11;
  2389. X        do {
  2390. X            s++;
  2391. X        } while (*s <= '9' && *s >= '0');
  2392. X        } else
  2393. X        max_tree_lines = upordown*6;
  2394. X        if (*s)
  2395. X        strncpy(select_order, s, 3);
  2396. X        if (mode == 'i')
  2397. X        use_threads = upordown;
  2398. X        else if (use_threads != upordown)
  2399. X        printf("You must exit and restart to turn threaded operation %s.\n\n",
  2400. X            upordown ? "on" : "off");
  2401. X#else
  2402. X        notincl("-x");
  2403. X#endif
  2404. X        break;
  2405. X    case 'X':
  2406. X#ifdef USETHREADS
  2407. X        s++;
  2408. X        if (*s == '=') s++;
  2409. X        if (*s <= '9' && *s >= '0') {
  2410. X        select_on = atoi(s);
  2411. X        do {
  2412. X            s++;
  2413. X        } while (*s <= '9' && *s >= '0');
  2414. X        } else
  2415. X        select_on = upordown;
  2416. X        if (*s)
  2417. X        end_select = *s++;
  2418. X        if (*s)
  2419. X        page_select = *s;
  2420. X#else
  2421. X        notincl("-X");
  2422. X#endif
  2423. X        break;
  2424. X    /*
  2425. X     * People want a way to avoid checking for new newsgroups on startup.
  2426. X     */
  2427. X    case 'q':
  2428. X        quickstart = upordown;
  2429. X        break;
  2430. X    default:
  2431. X#ifdef VERBOSE
  2432. X        IF(verbose)
  2433. X        printf("\nIgnoring unrecognized switch: -%c\n", *s) FLUSH;
  2434. X        ELSE
  2435. X#endif
  2436. X#ifdef TERSE
  2437. X        printf("\nIgnoring -%c\n", *s) FLUSH;
  2438. X#endif
  2439. X        break;
  2440. X    }
  2441. X    }
  2442. X}
  2443. X
  2444. X/* print current switch values */
  2445. X
  2446. Xvoid
  2447. Xpr_switches()
  2448. X{
  2449. X    static char mp[2] = {'+','-'};
  2450. X    register int i;
  2451. X    
  2452. X    fputs("\nCurrent switch settings:\n",stdout);
  2453. X    printf("%c/ ", mp[strEQ(getval("SAVEDIR",SAVEDIR),"%p/%c")]);
  2454. X    printf("%cc ", mp[checkflag]);
  2455. X    printf("-C%d ", docheckwhen);
  2456. X    printf("-d%s ", cwd);
  2457. X#ifdef DEBUGGING
  2458. X    if (debug)
  2459. X    printf("-D%d ", debug);
  2460. X#endif
  2461. X    printf("%ce ", mp[erase_screen]);
  2462. X    printf("-F\"%s\" ", indstr);
  2463. X#ifdef INNERSEARCH
  2464. X    printf("-g%d", gline);
  2465. X#endif
  2466. X    putchar('\n');
  2467. X#ifdef VERBOSE
  2468. X    if (verbose) {
  2469. X    for (i=HEAD_FIRST; i<HEAD_LAST; i++)
  2470. X        printf("%ch%s%c",
  2471. X        mp[htype[i].ht_flags & HT_HIDE], htype[i].ht_name,
  2472. X        (! (i % 5) ? '\n' : ' ') );
  2473. X    }
  2474. X#endif
  2475. X    printf("-i%d ", initlines);
  2476. X    printf("%cl ", mp[muck_up_clear]);
  2477. X#ifdef CLEAREOL
  2478. X    printf("%cL ", mp[can_home_clear]);
  2479. X#endif /* CLEAREOL */
  2480. X    if (marking)
  2481. X    printf("-m%c ",marking==UNDERLINE?'u':'s');
  2482. X    else
  2483. X    printf("+m ");
  2484. X    printf("%cM ", mp[mbox_always]);
  2485. X    printf("%cN ", mp[norm_always]);
  2486. X    printf("%cr ", mp[findlast]);
  2487. X    if (countdown)
  2488. X    printf("-s%d ", countdown);
  2489. X    else
  2490. X    printf("%cs ", mp[suppress_cn]);
  2491. X#ifdef ARTSEARCH
  2492. X    if (scanon)
  2493. X    printf("-S%d ",scanon);
  2494. X    else
  2495. X    printf("+S ");
  2496. X#endif
  2497. X#ifdef VERBOSE
  2498. X#ifdef TERSE
  2499. X    printf("%ct ", mp[!verbose]);
  2500. X#endif
  2501. X#endif
  2502. X    printf("%cT ", mp[typeahead]);
  2503. X#ifdef VERIFY
  2504. X    printf("%cv ", mp[verify]);
  2505. X#endif
  2506. X#ifdef USETHREADS
  2507. X    if (use_threads)
  2508. X    printf("-x%d%s ",max_tree_lines,select_order);
  2509. X    else
  2510. X    printf("+x ");
  2511. X    if (select_on)
  2512. X    printf("-X%d%c%c ",select_on,end_select,page_select);
  2513. X    else
  2514. X    printf("+X ");
  2515. X#endif
  2516. X    fputs("\n\n",stdout) FLUSH;
  2517. X#ifdef ONLY
  2518. X    if (maxngtodo) {
  2519. X#ifdef VERBOSE
  2520. X    IF(verbose)
  2521. X        fputs("Current restriction:",stdout);
  2522. X    ELSE
  2523. X#endif
  2524. X#ifdef TERSE
  2525. X        fputs("Only:",stdout);
  2526. X#endif
  2527. X    for (i=0; i<maxngtodo; i++)
  2528. X        printf(" %s",ngtodo[i]);
  2529. X    fputs("\n\n",stdout) FLUSH;
  2530. X    }
  2531. X#ifdef VERBOSE
  2532. X    else if (verbose)
  2533. X    fputs("No restriction.\n\n",stdout) FLUSH;
  2534. X#endif
  2535. X#endif
  2536. X}
  2537. X
  2538. Xvoid
  2539. Xcwd_check()
  2540. X{
  2541. X    char tmpbuf[LBUFLEN];
  2542. X
  2543. X    if (!cwd)
  2544. X    cwd = savestr(filexp("~/News"));
  2545. X    strcpy(tmpbuf,cwd);
  2546. X    if (chdir(cwd)) {
  2547. X    safecpy(tmpbuf,filexp(cwd),sizeof tmpbuf);
  2548. X    if (makedir(tmpbuf,MD_DIR) < 0 || chdir(tmpbuf) < 0) {
  2549. X        interp(cmd_buf, (sizeof cmd_buf), "%~/News");
  2550. X        if (makedir(cmd_buf,MD_DIR) < 0)
  2551. X        strcpy(tmpbuf,homedir);
  2552. X        else
  2553. X        strcpy(tmpbuf,cmd_buf);
  2554. X        chdir(tmpbuf);
  2555. X#ifdef VERBOSE
  2556. X        IF(verbose)
  2557. X        printf("\
  2558. XCannot make directory %s--\n\
  2559. X    articles will be saved to %s\n\
  2560. X\n\
  2561. X",cwd,tmpbuf) FLUSH;
  2562. X        ELSE
  2563. X#endif
  2564. X#ifdef TERSE
  2565. X        printf("\
  2566. XCan't make %s--\n\
  2567. X    using %s\n\
  2568. X\n\
  2569. X",cwd,tmpbuf) FLUSH;
  2570. X#endif
  2571. X    }
  2572. X    }
  2573. X    free(cwd);
  2574. X    getwd(tmpbuf);
  2575. X    if (eaccess(tmpbuf,2)) {
  2576. X#ifdef VERBOSE
  2577. X    IF(verbose)
  2578. X        printf("\
  2579. XCurrent directory %s is not writeable--\n\
  2580. X    articles will be saved to home directory\n\n\
  2581. X",tmpbuf) FLUSH;
  2582. X    ELSE
  2583. X#endif
  2584. X#ifdef TERSE
  2585. X        printf("%s not writeable--using ~\n\n",tmpbuf) FLUSH;
  2586. X#endif
  2587. X    strcpy(tmpbuf,homedir);
  2588. X    }
  2589. X    cwd = savestr(tmpbuf);
  2590. X}
  2591. END_OF_FILE
  2592.   if test 11791 -ne `wc -c <'sw.c'`; then
  2593.     echo shar: \"'sw.c'\" unpacked with wrong size!
  2594.   fi
  2595.   # end of 'sw.c'
  2596. fi
  2597. echo shar: End of archive 10 \(of 14\).
  2598. cp /dev/null ark10isdone
  2599. MISSING=""
  2600. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2601.     if test ! -f ark${I}isdone ; then
  2602.     MISSING="${MISSING} ${I}"
  2603.     fi
  2604. done
  2605. if test "${MISSING}" = "" ; then
  2606.     echo You have unpacked all 14 archives.
  2607.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2608. else
  2609.     echo You still must unpack the following archives:
  2610.     echo "        " ${MISSING}
  2611. fi
  2612. exit 0
  2613.